/**
 ******************************************************************************
 * @file    stm32f7xx_hal_sd.c
 * @author  MCD Application Team
 * @version V1.3.2
 * @date    26-June-2015
 * @brief   SD card HAL module driver.
 *          This file provides firmware functions to manage the following
 *          functionalities of the Secure Digital (SD) peripheral:
 *           + Initialization and de-initialization functions
 *           + IO operation functions
 *           + Peripheral Control functions
 *           + Peripheral State functions
 *
 * @verbatim
 * ==============================================================================
 ##### How to use this driver #####
 #####==============================================================================
 #####[..]
 #####This driver implements a high level communication layer for read and write from/to
 #####this memory. The needed STM32 hardware resources (SDMMC and GPIO) are performed by
 #####the user in HAL_SD_MspInit() function (MSP layer).
 #####Basically, the MSP layer configuration should be the same as we provide in the
 #####examples.
 #####You can easily tailor this configuration according to hardware resources.
 #####
 #####[..]
 #####This driver is a generic layered driver for SDMMC memories which uses the HAL
 #####SDMMC driver functions to interface with SD and uSD cards devices.
 #####It is used as follows:
 #####
 #####(#)Initialize the SDMMC low level resources by implement the HAL_SD_MspInit() API:
 #####  (##) Enable the SDMMC interface clock using __HAL_RCC_SDMMC_CLK_ENABLE();
 #####  (##) SDMMC pins configuration for SD card
 #####      (+++) Enable the clock for the SDMMC GPIOs using the functions __HAL_RCC_GPIOx_CLK_ENABLE();
 #####      (+++) Configure these SDMMC pins as alternate function pull-up using HAL_GPIO_Init()
 #####            and according to your pin assignment;
 #####  (##) DMA Configuration if you need to use DMA process (HAL_SD_ReadBlocks_DMA()
 #####       and HAL_SD_WriteBlocks_DMA() APIs).
 #####      (+++) Enable the DMAx interface clock using __HAL_RCC_DMAx_CLK_ENABLE();
 #####      (+++) Configure the DMA using the function HAL_DMA_Init() with predeclared and filled.
 #####  (##) NVIC configuration if you need to use interrupt process when using DMA transfer.
 #####      (+++) Configure the SDMMC and DMA interrupt priorities using functions
 #####            HAL_NVIC_SetPriority(); DMA priority is superior to SDMMC's priority
 #####      (+++) Enable the NVIC DMA and SDMMC IRQs using function HAL_NVIC_EnableIRQ()
 #####      (+++) SDMMC interrupts are managed using the macros __HAL_SD_SDMMC_ENABLE_IT()
 #####            and __HAL_SD_SDMMC_DISABLE_IT() inside the communication process.
 #####      (+++) SDMMC interrupts pending bits are managed using the macros __HAL_SD_SDMMC_GET_IT()
 #####            and __HAL_SD_SDMMC_CLEAR_IT()
 #####(#) At this stage, you can perform SD read/write/erase operations after SD card initialization
 #####
 #####
 *** SD Card Initialization and configuration ***
 ***================================================
 ***[..]
 ***To initialize the SD Card, use the HAL_SD_Init() function.  It Initializes
 ***the SD Card and put it into StandBy State (Ready for data transfer).
 ***This function provide the following operations:
 ***
 ***(#) Apply the SD Card initialization process at 400KHz and check the SD Card
 ***    type (Standard Capacity or High Capacity). You can change or adapt this
 ***    frequency by adjusting the "ClockDiv" field.
 ***    The SD Card frequency (SDMMC_CK) is computed as follows:
 ***
 ***       SDMMC_CK = SDMMCCLK / (ClockDiv + 2)
 ***
 ***    In initialization mode and according to the SD Card standard,
 ***    make sure that the SDMMC_CK frequency doesn't exceed 400KHz.
 ***
 ***(#) Get the SD CID and CSD data. All these information are managed by the SDCardInfo
 ***    structure. This structure provide also ready computed SD Card capacity
 ***    and Block size.
 ***
 ***    -@- These information are stored in SD handle structure in case of future use.
 ***
 ***(#) Configure the SD Card Data transfer frequency. By Default, the card transfer
 ***    frequency is set to 24MHz. You can change or adapt this frequency by adjusting
 ***    the "ClockDiv" field.
 ***    In transfer mode and according to the SD Card standard, make sure that the
 ***    SDMMC_CK frequency doesn't exceed 25MHz and 50MHz in High-speed mode switch.
 ***    To be able to use a frequency higher than 24MHz, you should use the SDMMC
 ***    peripheral in bypass mode. Refer to the corresponding reference manual
 ***    for more details.
 ***
 ***(#) Select the corresponding SD Card according to the address read with the step 2.
 ***
 ***(#) Configure the SD Card in wide bus mode: 4-bits data.
 ***
 *** SD Card Read operation ***
 ***==============================
 ***[..]
 ***(+) You can read from SD card in polling mode by using function HAL_SD_ReadBlocks().
 ***    This function support only 512-bytes block length (the block size should be
 ***    chosen as 512 bytes).
 ***    You can choose either one block read operation or multiple block read operation
 ***    by adjusting the "NumberOfBlocks" parameter.
 ***
 ***(+) You can read from SD card in DMA mode by using function HAL_SD_ReadBlocks_DMA().
 ***    This function support only 512-bytes block length (the block size should be
 ***    chosen as 512 bytes).
 ***    You can choose either one block read operation or multiple block read operation
 ***    by adjusting the "NumberOfBlocks" parameter.
 ***    After this, you have to call the function HAL_SD_CheckReadOperation(), to insure
 ***    that the read transfer is done correctly in both DMA and SD sides.
 ***
 *** SD Card Write operation ***
 ***===============================
 ***[..]
 ***(+) You can write to SD card in polling mode by using function HAL_SD_WriteBlocks().
 ***    This function support only 512-bytes block length (the block size should be
 ***    chosen as 512 bytes).
 ***    You can choose either one block read operation or multiple block read operation
 ***    by adjusting the "NumberOfBlocks" parameter.
 ***
 ***(+) You can write to SD card in DMA mode by using function HAL_SD_WriteBlocks_DMA().
 ***    This function support only 512-bytes block length (the block size should be
 ***    chosen as 512 byte).
 ***    You can choose either one block read operation or multiple block read operation
 ***    by adjusting the "NumberOfBlocks" parameter.
 ***    After this, you have to call the function HAL_SD_CheckWriteOperation(), to insure
 ***    that the write transfer is done correctly in both DMA and SD sides.
 ***
 *** SD card status ***
 ***======================
 ***[..]
 ***(+) At any time, you can check the SD Card status and get the SD card state
 ***    by using the HAL_SD_GetStatus() function. This function checks first if the
 ***    SD card is still connected and then get the internal SD Card transfer state.
 ***(+) You can also get the SD card SD Status register by using the HAL_SD_SendSDStatus()
 ***    function.
 ***
 *** SD HAL driver macros list ***
 ***==================================
 ***[..]
 ***Below the list of most used macros in SD HAL driver.
 ***
 ***(+) __HAL_SD_SDMMC_ENABLE : Enable the SD device
 ***(+) __HAL_SD_SDMMC_DISABLE : Disable the SD device
 ***(+) __HAL_SD_SDMMC_DMA_ENABLE: Enable the SDMMC DMA transfer
 ***(+) __HAL_SD_SDMMC_DMA_DISABLE: Disable the SDMMC DMA transfer
 ***(+) __HAL_SD_SDMMC_ENABLE_IT: Enable the SD device interrupt
 ***(+) __HAL_SD_SDMMC_DISABLE_IT: Disable the SD device interrupt
 ***(+) __HAL_SD_SDMMC_GET_FLAG:Check whether the specified SD flag is set or not
 ***(+) __HAL_SD_SDMMC_CLEAR_FLAG: Clear the SD's pending flags
 ***
 ***(@) You can refer to the SD HAL driver header file for more useful macros
 ***
 ***@endverbatim
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */

#include "FreeRTOS.h"
#include "task.h"

/* This include is not necessary except for including the definition of FF_PRINTF(). */
#include "ff_headers.h"

/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal.h"

#ifdef HAL_SD_MODULE_ENABLED

/** @addtogroup STM32F7xx_HAL_Driver
 * @{
 */

/** @addtogroup SD
 * @{
 */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/** @addtogroup SD_Private_Defines
 * @{
 */

/**
 * @brief  SDMMC Data block size
 */
    #define DATA_BLOCK_SIZE    ( ( uint32_t ) ( 9 << 4 ) )

/**
 * @brief  SDMMC Static flags, Timeout, FIFO Address
 */
    #define SDMMC_STATIC_FLAGS                                                      \
    ( ( uint32_t ) ( SDIO_FLAG_CCRCFAIL | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_CTIMEOUT | \
                     SDIO_FLAG_DTIMEOUT | SDIO_FLAG_TXUNDERR | SDIO_FLAG_RXOVERR |  \
                     SDIO_FLAG_CMDREND | SDIO_FLAG_CMDSENT | SDIO_FLAG_DATAEND |    \
                     SDIO_FLAG_DBCKEND ) )

    #define SDMMC_CMD0TIMEOUT               ( ( uint32_t ) 0x00010000 )

/**
 * @brief  Mask for errors Card Status R1 (OCR Register)
 */
    #define SD_OCR_ADDR_OUT_OF_RANGE        ( ( uint32_t ) 0x80000000 )
    #define SD_OCR_ADDR_MISALIGNED          ( ( uint32_t ) 0x40000000 )
    #define SD_OCR_BLOCK_LEN_ERR            ( ( uint32_t ) 0x20000000 )
    #define SD_OCR_ERASE_SEQ_ERR            ( ( uint32_t ) 0x10000000 )
    #define SD_OCR_BAD_ERASE_PARAM          ( ( uint32_t ) 0x08000000 )
    #define SD_OCR_WRITE_PROT_VIOLATION     ( ( uint32_t ) 0x04000000 )
    #define SD_OCR_LOCK_UNLOCK_FAILED       ( ( uint32_t ) 0x01000000 )
    #define SD_OCR_COM_CRC_FAILED           ( ( uint32_t ) 0x00800000 )
    #define SD_OCR_ILLEGAL_CMD              ( ( uint32_t ) 0x00400000 )
    #define SD_OCR_CARD_ECC_FAILED          ( ( uint32_t ) 0x00200000 )
    #define SD_OCR_CC_ERROR                 ( ( uint32_t ) 0x00100000 )
    #define SD_OCR_GENERAL_UNKNOWN_ERROR    ( ( uint32_t ) 0x00080000 )
    #define SD_OCR_STREAM_READ_UNDERRUN     ( ( uint32_t ) 0x00040000 )
    #define SD_OCR_STREAM_WRITE_OVERRUN     ( ( uint32_t ) 0x00020000 )
    #define SD_OCR_CID_CSD_OVERWRITE        ( ( uint32_t ) 0x00010000 )
    #define SD_OCR_WP_ERASE_SKIP            ( ( uint32_t ) 0x00008000 )
    #define SD_OCR_CARD_ECC_DISABLED        ( ( uint32_t ) 0x00004000 )
    #define SD_OCR_ERASE_RESET              ( ( uint32_t ) 0x00002000 )
    #define SD_OCR_AKE_SEQ_ERROR            ( ( uint32_t ) 0x00000008 )
    #define SD_OCR_ERRORBITS                ( ( uint32_t ) 0xFDFFE008 )

/**
 * @brief  Masks for R6 Response
 */
    #define SD_R6_GENERAL_UNKNOWN_ERROR     ( ( uint32_t ) 0x00002000 )
    #define SD_R6_ILLEGAL_CMD               ( ( uint32_t ) 0x00004000 )
    #define SD_R6_COM_CRC_FAILED            ( ( uint32_t ) 0x00008000 )

    #define SD_VOLTAGE_WINDOW_SD            ( ( uint32_t ) 0x80100000 )
    #define SD_HIGH_CAPACITY                ( ( uint32_t ) 0x40000000 )
    #define SD_STD_CAPACITY                 ( ( uint32_t ) 0x00000000 )
    #define SD_CHECK_PATTERN                ( ( uint32_t ) 0x000001AA )

    #define SD_MAX_VOLT_TRIAL               ( ( uint32_t ) 0x0000FFFF )
    #define SD_ALLZERO                      ( ( uint32_t ) 0x00000000 )

    #define SD_WIDE_BUS_SUPPORT             ( ( uint32_t ) 0x00040000 )
    #define SD_SINGLE_BUS_SUPPORT           ( ( uint32_t ) 0x00010000 )
    #define SD_CARD_LOCKED                  ( ( uint32_t ) 0x02000000 )

    #define SD_DATATIMEOUT                  ( ( uint32_t ) 0xFFFFFFFF )
    #define SD_0TO7BITS                     ( ( uint32_t ) 0x000000FF )
    #define SD_8TO15BITS                    ( ( uint32_t ) 0x0000FF00 )
    #define SD_16TO23BITS                   ( ( uint32_t ) 0x00FF0000 )
    #define SD_24TO31BITS                   ( ( uint32_t ) 0xFF000000 )
    #define SD_MAX_DATA_LENGTH              ( ( uint32_t ) 0x01FFFFFF )

    #define SD_HALFFIFO                     ( ( uint32_t ) 0x00000008 )
    #define SD_HALFFIFOBYTES                ( ( uint32_t ) 0x00000020 )

/**
 * @brief  Command Class Supported
 */
    #define SD_CCCC_LOCK_UNLOCK             ( ( uint32_t ) 0x00000080 )
    #define SD_CCCC_WRITE_PROT              ( ( uint32_t ) 0x00000040 )
    #define SD_CCCC_ERASE                   ( ( uint32_t ) 0x00000020 )

/**
 * @brief  Following commands are SD Card Specific commands.
 *         SDMMC_APP_CMD should be sent before sending these commands.
 */
    #define SD_SDMMC_SEND_IF_COND           ( ( uint32_t ) SD_CMD_HS_SEND_EXT_CSD )

/**
 * @}
 */

/* Private macro -------------------------------------------------------------*/

/* A few macro's that will allow to use the 'SDIO_' macro's that were
 * used in the earlier SDIO drivers. It makes it easier to compare the
 * sources. */

    #define SDIO_FLAG_CCRCFAIL                    SDMMC_FLAG_CCRCFAIL
    #define SDIO_FLAG_DCRCFAIL                    SDMMC_FLAG_DCRCFAIL
    #define SDIO_FLAG_CTIMEOUT                    SDMMC_FLAG_CTIMEOUT
    #define SDIO_FLAG_DTIMEOUT                    SDMMC_FLAG_DTIMEOUT
    #define SDIO_FLAG_TXUNDERR                    SDMMC_FLAG_TXUNDERR
    #define SDIO_FLAG_RXOVERR                     SDMMC_FLAG_RXOVERR
    #define SDIO_FLAG_CMDREND                     SDMMC_FLAG_CMDREND
    #define SDIO_FLAG_CMDSENT                     SDMMC_FLAG_CMDSENT
    #define SDIO_FLAG_DATAEND                     SDMMC_FLAG_DATAEND
    #define SDIO_FLAG_DBCKEND                     SDMMC_FLAG_DBCKEND
    #define SDIO_FLAG_RXDAVL                      SDMMC_FLAG_RXDAVL
    #define SDIO_FLAG_RXFIFOHF                    SDMMC_FLAG_RXFIFOHF
    #define SDIO_FLAG_RXACT                       SDMMC_FLAG_RXACT
    #define SDIO_FLAG_TXACT                       SDMMC_FLAG_TXACT
    #define SDIO_FLAG_TXFIFOHE                    SDMMC_FLAG_TXFIFOHE
    #define SDIO_FLAG_TXFIFOE                     SDMMC_FLAG_TXFIFOE

    #define SDIO_CmdInitTypeDef                   SDMMC_CmdInitTypeDef
    #define SDIO_DataInitTypeDef                  SDMMC_DataInitTypeDef
    #define SDIO_InitTypeDef                      SDMMC_InitTypeDef


    #define SDIO_BUS_WIDE_1B                      SDMMC_BUS_WIDE_1B
    #define SDIO_BUS_WIDE_4B                      SDMMC_BUS_WIDE_4B
    #define SDIO_BUS_WIDE_8B                      SDMMC_BUS_WIDE_8B
    #define SDIO_CLOCK_BYPASS_DISABLE             SDMMC_CLOCK_BYPASS_DISABLE
    #define SDIO_CLOCK_EDGE_RISING                SDMMC_CLOCK_EDGE_RISING
    #define SDIO_CLOCK_POWER_SAVE_DISABLE         SDMMC_CLOCK_POWER_SAVE_DISABLE
    #define SDIO_CPSM_ENABLE                      SDMMC_CPSM_ENABLE
    #define SDIO_DATABLOCK_SIZE_512B              SDMMC_DATABLOCK_SIZE_512B
    #define SDIO_DATABLOCK_SIZE_64B               SDMMC_DATABLOCK_SIZE_64B
    #define SDIO_DATABLOCK_SIZE_8B                SDMMC_DATABLOCK_SIZE_8B
    #define SDIO_DCTRL_DTEN                       SDMMC_DCTRL_DTEN
    #define SDIO_DPSM_ENABLE                      SDMMC_DPSM_ENABLE
    #define SDIO_HARDWARE_FLOW_CONTROL_DISABLE    SDMMC_HARDWARE_FLOW_CONTROL_DISABLE
    #define SDIO_HARDWARE_FLOW_CONTROL_ENABLE     SDMMC_HARDWARE_FLOW_CONTROL_ENABLE
    #define SDIO_INIT_CLK_DIV                     SDMMC_INIT_CLK_DIV
    #define SDIO_IT_DATAEND                       SDMMC_IT_DATAEND
    #define SDIO_IT_DCRCFAIL                      SDMMC_IT_DCRCFAIL
    #define SDIO_IT_DTIMEOUT                      SDMMC_IT_DTIMEOUT
    #define SDIO_IT_RXFIFOHF                      SDMMC_IT_RXFIFOHF
    #define SDIO_IT_RXOVERR                       SDMMC_IT_RXOVERR
    #define SDIO_IT_RXOVERR                       SDMMC_IT_RXOVERR
    #define SDIO_IT_TXFIFOHE                      SDMMC_IT_TXFIFOHE
    #define SDIO_IT_TXUNDERR                      SDMMC_IT_TXUNDERR
    #define SDIO_RESP1                            SDMMC_RESP1
    #define SDIO_RESP2                            SDMMC_RESP2
    #define SDIO_RESP3                            SDMMC_RESP3
    #define SDIO_RESP4                            SDMMC_RESP4
    #define SDIO_RESPONSE_LONG                    SDMMC_RESPONSE_LONG
    #define SDIO_RESPONSE_NO                      SDMMC_RESPONSE_NO
    #define SDIO_RESPONSE_SHORT                   SDMMC_RESPONSE_SHORT
    #define SDIO_TRANSFER_DIR_TO_CARD             SDMMC_TRANSFER_DIR_TO_CARD
    #define SDIO_TRANSFER_DIR_TO_SDIO             SDMMC_TRANSFER_DIR_TO_SDMMC
    #define SDIO_TRANSFER_MODE_BLOCK              SDMMC_TRANSFER_MODE_BLOCK
    #define SDIO_WAIT_NO                          SDMMC_WAIT_NO

    #ifdef __HAL_SD_SDIO_CLEAR_FLAG
        #undef __HAL_SD_SDIO_CLEAR_FLAG
    #endif

    #ifdef __HAL_SD_SDIO_GET_FLAG
        #undef __HAL_SD_SDIO_GET_FLAG
    #endif

    #ifdef SDIO_ReadFIFO
        #undef SDIO_ReadFIFO
    #endif

    #define __HAL_SD_SDIO_CLEAR_FLAG    __HAL_SD_SDMMC_CLEAR_FLAG
    #define __HAL_SD_SDIO_GET_FLAG      __HAL_SD_SDMMC_GET_FLAG
    #define SDIO_ReadFIFO               SDMMC_ReadFIFO
    #define SDIO_SendCommand            SDMMC_SendCommand
    #define SDIO_Init                   SDMMC_Init
    #define SDIO_GetResponse            SDMMC_GetResponse
    #define SDIO_DataConfig             SDMMC_DataConfig
    #define SDIO_GetPowerState          SDMMC_GetPowerState
    #define SDIO_PowerState_ON          SDMMC_PowerState_ON
    #define SDIO_PowerState_OFF         SDMMC_PowerState_OFF
    #define SDIO_GetCommandResponse     SDMMC_GetCommandResponse

    #define SDIO_STATIC_FLAGS           SDMMC_STATIC_FLAGS

/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup SD_Private_Functions SD Private Functions
 * @{
 */
    static HAL_SD_ErrorTypedef SD_Initialize_Cards( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_Select_Deselect( SD_HandleTypeDef * hsd,
                                                   uint64_t addr );
    static HAL_SD_ErrorTypedef SD_PowerON( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_PowerOFF( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_SendStatus( SD_HandleTypeDef * hsd,
                                              uint32_t * pCardStatus );
    static HAL_SD_CardStateTypedef SD_GetState( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_IsCardProgramming( SD_HandleTypeDef * hsd,
                                                     uint8_t * pStatus );
    static HAL_SD_ErrorTypedef SD_CmdError( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_CmdResp1Error( SD_HandleTypeDef * hsd,
                                                 uint8_t SD_CMD );
    static HAL_SD_ErrorTypedef SD_CmdResp7Error( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_CmdResp3Error( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_CmdResp2Error( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_CmdResp6Error( SD_HandleTypeDef * hsd,
                                                 uint8_t SD_CMD,
                                                 uint16_t * pRCA );
    static HAL_SD_ErrorTypedef SD_WideBus_Enable( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_WideBus_Disable( SD_HandleTypeDef * hsd );
    static HAL_SD_ErrorTypedef SD_FindSCR( SD_HandleTypeDef * hsd,
                                           uint32_t * pSCR );
    static void SD_DMA_RxCplt( DMA_HandleTypeDef * hdma );
    static void SD_DMA_RxError( DMA_HandleTypeDef * hdma );
    static void SD_DMA_TxCplt( DMA_HandleTypeDef * hdma );
    static void SD_DMA_TxError( DMA_HandleTypeDef * hdma );

/**
 * @}
 */
/* Exported functions --------------------------------------------------------*/

/** @addtogroup SD_Exported_Functions
 * @{
 */

/** @addtogroup SD_Exported_Functions_Group1
 *  @brief   Initialization and de-initialization functions
 *
 * @verbatim
 * ==============================================================================
 ##### Initialization and de-initialization functions #####
 #####==============================================================================
 #####[..]
 #####This section provides functions allowing to initialize/de-initialize the SD
 #####card device to be ready for use.
 #####
 #####
 #####@endverbatim
 * @{
 */

/**
 * @brief  Initializes the SD card according to the specified parameters in the
 *          SD_HandleTypeDef and create the associated handle.
 * @param  hsd SD handle
 * @param  SDCardInfo HAL_SD_CardInfoTypedef structure for SD card information
 * @retval HAL SD error state
 */
    HAL_SD_ErrorTypedef HAL_SD_Init( SD_HandleTypeDef * hsd,
                                     HAL_SD_CardInfoTypedef * SDCardInfo )
    {
        __IO HAL_SD_ErrorTypedef errorstate = SD_OK;
        SD_InitTypeDef tmpinit;

        /* Allocate lock resource and initialize it */
        hsd->Lock = HAL_UNLOCKED;

        /* Initialize the low level hardware (MSP) */
        HAL_SD_MspInit( hsd );

        /* Default SDMMC peripheral configuration for SD card initialization */
        tmpinit.ClockEdge = SDIO_CLOCK_EDGE_RISING;
        tmpinit.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
        tmpinit.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
        #if ( BUS_4BITS != 0 )
        {
            #warning Four bits
            tmpinit.BusWide = SDIO_BUS_WIDE_4B;
        }
        #else
        {
            #warning One bit
            tmpinit.BusWide = SDIO_BUS_WIDE_1B;
        }
        #endif
        tmpinit.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
        tmpinit.ClockDiv = SDIO_INIT_CLK_DIV;

        /* Initialize SDMMC peripheral interface with default configuration */
        SDIO_Init( hsd->Instance, tmpinit );

        /* Identify card operating voltage */
        errorstate = SD_PowerON( hsd );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Initialize the present SDIO card(s) and put them in idle state */
        errorstate = SD_Initialize_Cards( hsd );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Read CSD/CID MSD registers */
        errorstate = HAL_SD_Get_CardInfo( hsd, SDCardInfo );

        if( errorstate == SD_OK )
        {
            /* Select the Card */
            errorstate = SD_Select_Deselect( hsd, ( uint32_t ) ( ( ( uint32_t ) SDCardInfo->RCA ) << 16 ) );
        }

        /* Configure SDIO peripheral interface */
        SDIO_Init( hsd->Instance, hsd->Init );

        return errorstate;
    }

/**
 * @brief  De-Initializes the SD card.
 * @param  hsd SD handle
 * @retval HAL status
 */
    HAL_StatusTypeDef HAL_SD_DeInit( SD_HandleTypeDef * hsd )
    {
        /* Set SD power state to off */
        SD_PowerOFF( hsd );

        /* De-Initialize the MSP layer */
        HAL_SD_MspDeInit( hsd );

        return HAL_OK;
    }


/**
 * @brief  Initializes the SD MSP.
 * @param  hsd SD handle
 * @retval None
 */
    __weak void HAL_SD_MspInit( SD_HandleTypeDef * hsd )
    {
        /* NOTE : This function Should not be modified, when the callback is needed,
         *        the HAL_SD_MspInit could be implemented in the user file
         */
    }

/**
 * @brief  De-Initialize SD MSP.
 * @param  hsd SD handle
 * @retval None
 */
    __weak void HAL_SD_MspDeInit( SD_HandleTypeDef * hsd )
    {
        /* NOTE : This function Should not be modified, when the callback is needed,
         *        the HAL_SD_MspDeInit could be implemented in the user file
         */
    }

/**
 * @}
 */

/** @addtogroup SD_Exported_Functions_Group2
 *  @brief   Data transfer functions
 *
 * @verbatim
 * ==============================================================================
 ##### IO operation functions #####
 #####==============================================================================
 #####[..]
 #####This subsection provides a set of functions allowing to manage the data
 #####transfer from/to SD card.
 #####
 #####@endverbatim
 * @{
 */

/**
 * @brief  Reads block(s) from a specified address in a card. The Data transfer
 *         is managed by polling mode.
 * @param  hsd SD handle
 * @param  pReadBuffer pointer to the buffer that will contain the received data
 * @param  ReadAddr Address from where data is to be read
 * @param  BlockSize SD card Data block size
 * @note   BlockSize must be 512 bytes.
 * @param  NumberOfBlocks Number of SD blocks to read
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_ReadBlocks( SD_HandleTypeDef * hsd,
                                           uint32_t * pReadBuffer,
                                           uint64_t ReadAddr,
                                           uint32_t NumberOfBlocks )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        SDIO_DataInitTypeDef sdmmc_datainitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t count = 0, * tempbuff = ( uint32_t * ) pReadBuffer;
        __IO uint32_t * pulFIFO = &( hsd->Instance->FIFO );
        const uint32_t BlockSize = 512U;

        /* Initialize data control register */
        hsd->Instance->DCTRL = 0;

        if( hsd->CardType == HIGH_CAPACITY_SD_CARD )
        {
            ReadAddr /= BlockSize;
        }

        /* Set Block Size for Card */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) BlockSize;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SET_BLOCKLEN );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Configure the SD DPSM (Data Path State Machine) */
        sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT;
        sdmmc_datainitstructure.DataLength = NumberOfBlocks * BlockSize;
        sdmmc_datainitstructure.DataBlockSize = DATA_BLOCK_SIZE;
        sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
        sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
        sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE;
        SDIO_DataConfig( hsd->Instance, &sdmmc_datainitstructure );

        if( NumberOfBlocks > 1 )
        {
            /* Send CMD18 READ_MULT_BLOCK with argument data address */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_MULT_BLOCK;
        }
        else
        {
            /* Send CMD17 READ_SINGLE_BLOCK */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
        }

        sdmmc_cmdinitstructure.Argument = ( uint32_t ) ReadAddr;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, sdmmc_cmdinitstructure.CmdIndex );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Read block(s) in polling mode */
        if( NumberOfBlocks > 1 )
        {
            /* Poll on SDIO flags */
            while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND ) )
            {
                if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXFIFOHF ) )
                {
                    /* Read data from SDIO Rx FIFO */
                    tempbuff[ 0 ] = *( pulFIFO );
                    tempbuff[ 1 ] = *( pulFIFO );
                    tempbuff[ 2 ] = *( pulFIFO );
                    tempbuff[ 3 ] = *( pulFIFO );
                    tempbuff[ 4 ] = *( pulFIFO );
                    tempbuff[ 5 ] = *( pulFIFO );
                    tempbuff[ 6 ] = *( pulFIFO );
                    tempbuff[ 7 ] = *( pulFIFO );

                    tempbuff += 8;
                }
            }
        }
        else
        {
            /* In case of single block transfer, no need of stop transfer at all */
            while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND ) )
            {
                if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXFIFOHF ) )
                {
                    /* Read data from SDIO Rx FIFO */
                    tempbuff[ 0 ] = *( pulFIFO );
                    tempbuff[ 1 ] = *( pulFIFO );
                    tempbuff[ 2 ] = *( pulFIFO );
                    tempbuff[ 3 ] = *( pulFIFO );
                    tempbuff[ 4 ] = *( pulFIFO );
                    tempbuff[ 5 ] = *( pulFIFO );
                    tempbuff[ 6 ] = *( pulFIFO );
                    tempbuff[ 7 ] = *( pulFIFO );

                    tempbuff += 8;
                }
            }
        }

        /* Send stop transmission command in case of multiblock read */
        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DATAEND ) && ( NumberOfBlocks > 1 ) )
        {
            if( ( hsd->CardType == STD_CAPACITY_SD_CARD_V1_1 ) || \
                ( hsd->CardType == STD_CAPACITY_SD_CARD_V2_0 ) || \
                ( hsd->CardType == HIGH_CAPACITY_SD_CARD ) )
            {
                /* Send stop transmission command */
                errorstate = HAL_SD_StopTransfer( hsd );
            }
        }

        /* Get error state */
        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DTIMEOUT ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DTIMEOUT );

            errorstate = SD_DATA_TIMEOUT;

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DCRCFAIL ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DCRCFAIL );

            errorstate = SD_DATA_CRC_FAIL;

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_RXOVERR );

            errorstate = SD_RX_OVERRUN;

            return errorstate;
        }
        else
        {
            /* Note that the STM32F7 doesn't have a SDIO_FLAG_STBITERR flag. */
            /* No error flag set */
        }

        count = SD_DATATIMEOUT;

        /* Empty FIFO if there is still any data */
        while( ( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXDAVL ) ) && ( count > 0 ) )
        {
            *tempbuff = SDIO_ReadFIFO( hsd->Instance );
            tempbuff++;
            count--;
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        return errorstate;
    }

/**
 * @brief  Allows to write block(s) to a specified address in a card. The Data
 *         transfer is managed by polling mode.
 * @param  hsd SD handle
 * @param  pWriteBuffer pointer to the buffer that will contain the data to transmit
 * @param  WriteAddr Address from where data is to be written
 * @param  BlockSize SD card Data block size
 * @note   BlockSize must be 512 bytes.
 * @param  NumberOfBlocks Number of SD blocks to write
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_WriteBlocks( SD_HandleTypeDef * hsd,
                                            uint32_t * pWriteBuffer,
                                            uint64_t WriteAddr,
                                            uint32_t NumberOfBlocks )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
/*SDIO_DataInitTypeDef sdmmc_datainitstructure; */
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t totalNumberOfBytes, bytesRemaining;
        uint32_t tmpreg;
        uint32_t last_sta;
        uint32_t * tempbuff = ( uint32_t * ) pWriteBuffer;
        uint8_t cardstate = 0;
        __IO uint32_t * pulFIFO = &( hsd->Instance->FIFO );
        uint32_t ulEndFags;
        uint32_t ulHasHWFlowControl;
        const uint32_t BlockSize = 512U;

        /* Initialize data control register */
        hsd->Instance->DCTRL = 0;

        if( hsd->CardType == HIGH_CAPACITY_SD_CARD )
        {
            WriteAddr /= BlockSize;
        }

        /* Set Block Size for Card */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) BlockSize;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SET_BLOCKLEN );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        if( NumberOfBlocks > 1 )
        {
            /* Send CMD25 WRITE_MULT_BLOCK with argument data address */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_MULT_BLOCK;
            /* Test for DATAEND : Data end (data counter, SDID count) is zero) */
            ulEndFags = SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND;
        }
        else
        {
            /* Send CMD24 WRITE_SINGLE_BLOCK */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;
            /* Test for DBCKEND : Data Block Sent/Received (CRC check passed) */
            ulEndFags = SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND;
        }

        ulEndFags |= SDIO_FLAG_TXUNDERR;

        sdmmc_cmdinitstructure.Argument = ( uint32_t ) WriteAddr;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, sdmmc_cmdinitstructure.CmdIndex );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        ulHasHWFlowControl = ( hsd->Instance->CLKCR & SDIO_HARDWARE_FLOW_CONTROL_ENABLE ) != 0;

        /* Set total number of bytes to write */
        totalNumberOfBytes = NumberOfBlocks * BlockSize;
        bytesRemaining = 4 * ( ( totalNumberOfBytes + 3 ) / 4 );

        /* Configure the SD DPSM (Data Path State Machine) */

/*
 * sdio_datainitstructure.DataTimeOut   = SD_DATATIMEOUT;
 * sdio_datainitstructure.DataLength    = NumberOfBlocks * BlockSize;
 * sdio_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
 * sdio_datainitstructure.TransferDir   = SDIO_TRANSFER_DIR_TO_CARD;
 * sdio_datainitstructure.TransferMode  = SDIO_TRANSFER_MODE_BLOCK;
 * sdio_datainitstructure.DPSM          = SDIO_DPSM_ENABLE;
 * SDIO_DataConfig(hsd->Instance, &sdio_datainitstructure);
 */
        /* Set the SDIO Data Timeout value */
        hsd->Instance->DTIMER = SD_DATATIMEOUT;

        /* Set the SDIO DataLength value */
        hsd->Instance->DLEN = NumberOfBlocks * BlockSize;

        tmpreg = hsd->Instance->DCTRL & ~( DCTRL_CLEAR_MASK );
        /* Set the SDIO data configuration parameters */
        tmpreg |= ( uint32_t ) ( SDIO_DATABLOCK_SIZE_512B | SDIO_TRANSFER_DIR_TO_CARD | SDIO_TRANSFER_MODE_BLOCK | SDIO_DCTRL_DTEN );

        /* Write to SDIO DCTRL */

        hsd->Instance->DCTRL = tmpreg;

        for( ; ; )
        {
            last_sta = hsd->Instance->STA;

            if( ( last_sta & ( SDIO_FLAG_TXFIFOHE | SDIO_FLAG_TXFIFOE ) ) != 0 )
            {
                /* SDIO_FLAG_TXFIFOHE: Transmit FIFO Half Empty
                 * May write 32 bytes. */
                if( bytesRemaining < 32 )
                {
                    /* Write data to SDIO Tx FIFO */
                    while( bytesRemaining > 0 )
                    {
                        *pulFIFO = *( tempbuff++ );
                        bytesRemaining -= 4;
                    }
                }
                else
                {
                    /* Write data to SDIO Tx FIFO */
                    *pulFIFO = tempbuff[ 0 ];
                    *pulFIFO = tempbuff[ 1 ];
                    *pulFIFO = tempbuff[ 2 ];
                    *pulFIFO = tempbuff[ 3 ];
                    *pulFIFO = tempbuff[ 4 ];
                    *pulFIFO = tempbuff[ 5 ];
                    *pulFIFO = tempbuff[ 6 ];
                    *pulFIFO = tempbuff[ 7 ];

                    tempbuff += 8;
                    bytesRemaining -= 32;

                    if( ( last_sta & SDIO_FLAG_TXFIFOE ) != 0 )
                    {
                        /* SDIO_FLAG_TXFIFOE:  Transmit FIFO empty
                         * May write 24 or 32 extra bytes, depending on
                         * ulHasHWFlowControl. */
                        *pulFIFO = tempbuff[ 0 ];
                        *pulFIFO = tempbuff[ 1 ];
                        *pulFIFO = tempbuff[ 2 ];
                        *pulFIFO = tempbuff[ 3 ];
                        *pulFIFO = tempbuff[ 4 ];
                        *pulFIFO = tempbuff[ 5 ];

                        if( ulHasHWFlowControl != 0 )
                        {
                            tempbuff += 6;
                            bytesRemaining -= 24;
                        }
                        else
                        {
                            *pulFIFO = tempbuff[ 6 ];
                            *pulFIFO = tempbuff[ 7 ];

                            tempbuff += 8;
                            bytesRemaining -= 32;
                        }
                    }
                }
            }

            if( ( last_sta & ulEndFags ) != 0 )
            {
                break;
            }
        }

        if( ( ( last_sta & SDIO_FLAG_TXUNDERR ) != 0 ) || ( bytesRemaining != 0 ) )
        {
            FF_PRINTF( "TX underflow %lu < %lu\n", bytesRemaining, totalNumberOfBytes );
        }

        /* Send stop transmission command in case of multiblock write */
        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DATAEND ) && ( NumberOfBlocks > 1 ) )
        {
            if( ( hsd->CardType == STD_CAPACITY_SD_CARD_V1_1 ) || ( hsd->CardType == STD_CAPACITY_SD_CARD_V2_0 ) || \
                ( hsd->CardType == HIGH_CAPACITY_SD_CARD ) )
            {
                /* Send stop transmission command */
                errorstate = HAL_SD_StopTransfer( hsd );
            }
        }

        /* Get error state */
        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DTIMEOUT ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DTIMEOUT );

            errorstate = SD_DATA_TIMEOUT;

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DCRCFAIL ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DCRCFAIL );

            errorstate = SD_DATA_CRC_FAIL;

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_TXUNDERR ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_TXUNDERR );

            errorstate = SD_TX_UNDERRUN;

            return errorstate;
        }
        else
        {
            /* Note that the STM32F7 doesn't have a SDIO_FLAG_STBITERR flag. */
            /* No error flag set */
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        /* Wait till the card is in programming state */
        do
        {
            errorstate = SD_IsCardProgramming( hsd, &cardstate );
        } while( ( errorstate == SD_OK ) && ( ( cardstate == SD_CARD_PROGRAMMING ) || ( cardstate == SD_CARD_RECEIVING ) ) );

        return errorstate;
    }

/**
 * @brief  Reads block(s) from a specified address in a card. The Data transfer
 *         is managed by DMA mode.
 * @note   This API should be followed by the function HAL_SD_CheckReadOperation()
 *         to check the completion of the read process
 * @param  hsd SD handle
 * @param  pReadBuffer Pointer to the buffer that will contain the received data
 * @param  ReadAddr Address from where data is to be read
 * @param  BlockSize SD card Data block size
 * @note   BlockSize must be 512 bytes.
 * @param  NumberOfBlocks Number of blocks to read.
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA( SD_HandleTypeDef * hsd,
                                               uint32_t * pReadBuffer,
                                               uint64_t ReadAddr,
                                               uint32_t NumberOfBlocks )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        SDIO_DataInitTypeDef sdmmc_datainitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        const uint32_t BlockSize = 512U;

        if( hsd->CardType == HIGH_CAPACITY_SD_CARD )
        {
            ReadAddr /= BlockSize;
        }

        /* Initialize data control register */
        hsd->Instance->DCTRL = 0;

        /* Initialize handle flags */
        hsd->SdTransferCplt = 0;
        hsd->DmaTransferCplt = 0;
        hsd->SdTransferErr = SD_OK;

        if( hsd->EventSetupFunction != NULL )
        {
            hsd->EventSetupFunction( hsd );
        }

        /* Initialize SD Read operation */
        if( NumberOfBlocks > 1 )
        {
            hsd->SdOperation = SD_READ_MULTIPLE_BLOCK;
        }
        else
        {
            hsd->SdOperation = SD_READ_SINGLE_BLOCK;
        }

        /* Enable transfer interrupts */
        __HAL_SD_SDIO_ENABLE_IT( hsd, ( SDIO_IT_DCRCFAIL | \
                                        SDIO_IT_DTIMEOUT | \
                                        SDIO_IT_DATAEND |  \
                                        SDIO_IT_RXOVERR ) );

        /* Enable SDIO DMA transfer */
        __HAL_SD_SDIO_DMA_ENABLE( hsd );

        /* Configure DMA user callbacks */
        hsd->hdmarx->XferCpltCallback = SD_DMA_RxCplt;
        hsd->hdmarx->XferErrorCallback = SD_DMA_RxError;

        /* Enable the DMA Stream */
        HAL_DMA_Start_IT( hsd->hdmarx, ( uint32_t ) &hsd->Instance->FIFO, ( uint32_t ) pReadBuffer, ( uint32_t ) ( BlockSize * NumberOfBlocks ) / 4 );

        /* Set Block Size for Card */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) BlockSize;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SET_BLOCKLEN );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Configure the SD DPSM (Data Path State Machine) */
        sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT;
        sdmmc_datainitstructure.DataLength = BlockSize * NumberOfBlocks;
        sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
        sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
        sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
        sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE;
        SDIO_DataConfig( hsd->Instance, &sdmmc_datainitstructure );

        /* Check number of blocks command */
        if( NumberOfBlocks > 1 )
        {
            /* Send CMD18 READ_MULT_BLOCK with argument data address */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_MULT_BLOCK;
        }
        else
        {
            /* Send CMD17 READ_SINGLE_BLOCK */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
        }

        sdmmc_cmdinitstructure.Argument = ( uint32_t ) ReadAddr;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, sdmmc_cmdinitstructure.CmdIndex );

        /* Update the SD transfer error in SD handle */
        hsd->SdTransferErr = errorstate;

        return errorstate;
    }


/**
 * @brief  Writes block(s) to a specified address in a card. The Data transfer
 *         is managed by DMA mode.
 * @note   This API should be followed by the function HAL_SD_CheckWriteOperation()
 *         to check the completion of the write process (by SD current status polling).
 * @param  hsd SD handle
 * @param  pWriteBuffer pointer to the buffer that will contain the data to transmit
 * @param  WriteAddr Address from where data is to be read
 * @param  BlockSize the SD card Data block size
 * @note   BlockSize must be 512 bytes.
 * @param  NumberOfBlocks Number of blocks to write
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA( SD_HandleTypeDef * hsd,
                                                uint32_t * pWriteBuffer,
                                                uint64_t WriteAddr,
                                                uint32_t NumberOfBlocks )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
/*SDIO_DataInitTypeDef sdmmc_datainitstructure;*/
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t tmpreg;
        const uint32_t BlockSize = 512U;

        if( hsd->CardType == HIGH_CAPACITY_SD_CARD )
        {
            WriteAddr /= BlockSize;
        }

        /* Initialize data control register */
        hsd->Instance->DCTRL = 0;

        /* Initialize handle flags */
        hsd->SdTransferCplt = 0;
        hsd->DmaTransferCplt = 0;
        hsd->SdTransferErr = SD_OK;

        if( hsd->EventSetupFunction != NULL )
        {
            hsd->EventSetupFunction( hsd );
        }

        hsd->Instance->DLEN = NumberOfBlocks * BlockSize;

        /* Initialize SD Write operation */
        if( NumberOfBlocks > 1 )
        {
            hsd->SdOperation = SD_WRITE_MULTIPLE_BLOCK;
        }
        else
        {
            hsd->SdOperation = SD_WRITE_SINGLE_BLOCK;
        }

        /* Enable transfer interrupts */
        __HAL_SD_SDIO_ENABLE_IT( hsd, ( SDIO_IT_DCRCFAIL | \
                                        SDIO_IT_DTIMEOUT | \
                                        SDIO_IT_DATAEND |  \
                                        SDIO_IT_TXUNDERR ) );

        /* Configure DMA user callbacks */
        hsd->hdmatx->XferCpltCallback = SD_DMA_TxCplt;
        hsd->hdmatx->XferErrorCallback = SD_DMA_TxError;

        /* Enable the DMA Stream */
        HAL_DMA_Start_IT( hsd->hdmatx, ( uint32_t ) pWriteBuffer, ( uint32_t ) &hsd->Instance->FIFO, ( uint32_t ) ( BlockSize * NumberOfBlocks ) / 4 );

        /* Enable SDIO DMA transfer */
        __HAL_SD_SDIO_DMA_ENABLE( hsd );

        /* Set Block Size for Card */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) BlockSize;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SET_BLOCKLEN );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Check number of blocks command */
        if( NumberOfBlocks <= 1 )
        {
            /* Send CMD24 WRITE_SINGLE_BLOCK */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;
        }
        else
        {
            /* Send CMD25 WRITE_MULT_BLOCK with argument data address */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_MULT_BLOCK;
        }

        sdmmc_cmdinitstructure.Argument = ( uint32_t ) WriteAddr;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, sdmmc_cmdinitstructure.CmdIndex );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Configure the SD DPSM (Data Path State Machine) */

/*
 * sdmmc_datainitstructure.DataTimeOut   = SD_DATATIMEOUT;
 * sdmmc_datainitstructure.DataLength    = BlockSize * NumberOfBlocks;
 * sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
 * sdmmc_datainitstructure.TransferDir   = SDIO_TRANSFER_DIR_TO_CARD;
 * sdmmc_datainitstructure.TransferMode  = SDIO_TRANSFER_MODE_BLOCK;
 * sdmmc_datainitstructure.DPSM          = SDIO_DPSM_ENABLE;
 * SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure);
 */

        /* Set the SDIO Data Timeout value */
        hsd->Instance->DTIMER = SD_DATATIMEOUT;

/*  / * Set the SDIO DataLength value * / */
/*  hsd->Instance->DLEN = NumberOfBlocks * BlockSize; */

        tmpreg = hsd->Instance->DCTRL & ~( DCTRL_CLEAR_MASK );
        /* Set the SDIO data configuration parameters */
        tmpreg |= ( uint32_t ) ( SDIO_DATABLOCK_SIZE_512B | SDIO_TRANSFER_DIR_TO_CARD | SDIO_TRANSFER_MODE_BLOCK | SDIO_DCTRL_DTEN );

        /* Write to SDIO DCTRL */
        hsd->Instance->DCTRL = tmpreg;

        hsd->SdTransferErr = errorstate;

        return errorstate;
    }

/**
 * @brief  This function waits until the SD DMA data read transfer is finished.
 *         This API should be called after HAL_SD_ReadBlocks_DMA() function
 *         to insure that all data sent by the card is already transferred by the
 *         DMA controller.
 * @param  hsd SD handle
 * @param  Timeout Timeout duration
 * @retval SD Card error state
 */

    HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation( SD_HandleTypeDef * hsd,
                                                   uint32_t ulMaxTime )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t ulStarted = xTaskGetTickCount();
        BaseType_t xHadTimeout = pdFALSE;

        /* Wait for DMA/SD transfer end or SD error variables to be in SD handle */

        while( 1 )
        {
            HAL_SD_ErrorTypedef xError;

            if( ( hsd->DmaTransferCplt != 0 ) && ( hsd->SdTransferCplt != 0 ) )
            {
                HAL_DMA_Abort( hsd->hdmarx );
                break;
            }

            xError = ( HAL_SD_ErrorTypedef ) hsd->SdTransferErr;

            if( xError != SD_OK )
            {
                break;
            }

            if( hsd->EventWaitFunction != NULL )
            {
                if( hsd->EventWaitFunction( ( void * ) hsd ) != 0 )
                {
                    FF_PRINTF( "EventWaitFunction: RX timeout!\n" );
                    /* A timeout is reached. */
                    break;
                }
            }
            else
            {
                if( ( xTaskGetTickCount() - ulStarted ) >= ulMaxTime )
                {
                    xHadTimeout = pdTRUE;
                    break;
                }
            }
        }

        ulStarted = xTaskGetTickCount();

        /* Wait until the Rx transfer is no longer active */
        while( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXACT ) )
        {
            if( ( xTaskGetTickCount() - ulStarted ) >= ulMaxTime )
            {
                xHadTimeout = pdTRUE;
                break;
            }
        }

        /* Send stop command in multiblock read */
        if( hsd->SdOperation == SD_READ_MULTIPLE_BLOCK )
        {
            errorstate = HAL_SD_StopTransfer( hsd );
        }

        if( ( xHadTimeout != pdFALSE ) && ( errorstate == SD_OK ) )
        {
            errorstate = SD_DATA_TIMEOUT;
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        /* Return error state */
        if( hsd->SdTransferErr != SD_OK )
        {
            return ( HAL_SD_ErrorTypedef ) hsd->SdTransferErr;
        }

        return errorstate;
    }

/**
 * @brief  This function waits until the SD DMA data write transfer is finished.
 *         This API should be called after HAL_SD_WriteBlocks_DMA() function
 *         to insure that all data sent by the card is already transferred by the
 *         DMA controller.
 * @param  hsd SD handle
 * @param  Timeout Timeout duration
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation( SD_HandleTypeDef * hsd,
                                                    uint32_t ulMaxTime )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t ulStarted = 0;
        BaseType_t xHadTimeout = pdFALSE;

        /* Wait for DMA/SD transfer end or SD error variables to be in SD handle */

        while( 1 )
        {
            HAL_SD_ErrorTypedef xError;

            if( ( hsd->DmaTransferCplt != 0 ) && ( hsd->SdTransferCplt != 0 ) )
            {
                HAL_DMA_Abort( hsd->hdmatx );
                break;
            }

            xError = ( HAL_SD_ErrorTypedef ) hsd->SdTransferErr;

            if( xError != SD_OK )
            {
                break;
            }

            if( hsd->EventWaitFunction != NULL )
            {
                if( hsd->EventWaitFunction( ( void * ) hsd ) != 0 )
                {
                    FF_PRINTF( "EventWaitFunction: TX timeout!\n" );
                    /* A timeout is reached. */
                    break;
                }
            }
            else
            {
                if( ( xTaskGetTickCount() - ulStarted ) >= ulMaxTime )
                {
                    xHadTimeout = pdTRUE;
                    break;
                }
            }
        }

        ulStarted = xTaskGetTickCount();

        /* Wait until the Tx transfer is no longer active */
        /* while( ( hsd->Instance->STA & SDIO_FLAG_TXACT ) != 0 ) { } */
        while( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_TXACT ) )
        {
            if( ( xTaskGetTickCount() - ulStarted ) >= ulMaxTime )
            {
                xHadTimeout = pdTRUE;
                break;
            }
        }

        /* Send stop command in multiblock write */
        if( hsd->SdOperation == SD_WRITE_MULTIPLE_BLOCK )
        {
            errorstate = HAL_SD_StopTransfer( hsd );
        }

        if( ( xHadTimeout != pdFALSE ) && ( errorstate == SD_OK ) )
        {
            errorstate = SD_DATA_TIMEOUT;
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        /* Return error state */
        if( hsd->SdTransferErr != SD_OK )
        {
            errorstate = ( HAL_SD_ErrorTypedef ) ( hsd->SdTransferErr );
        }
        else
        {
            /* Wait until write is complete */
            while( HAL_SD_GetStatus( hsd ) != SD_TRANSFER_OK )
            {
            }
        }

        return errorstate;
    }

/**
 * @brief  Erases the specified memory area of the given SD card.
 * @param  hsd SD handle
 * @param  startaddr Start byte address
 * @param  endaddr End byte address
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_Erase( SD_HandleTypeDef * hsd,
                                      uint64_t startaddr,
                                      uint64_t endaddr )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;

        uint32_t delay = 0;
        __IO uint32_t maxdelay = 0;
        uint8_t cardstate = 0;

        /* Check if the card command class supports erase command */
        if( ( ( hsd->CSD[ 1 ] >> 20 ) & SD_CCCC_ERASE ) == 0 )
        {
            errorstate = SD_REQUEST_NOT_APPLICABLE;

            return errorstate;
        }

        /* Get max delay value */
        maxdelay = 120000 / ( ( ( hsd->Instance->CLKCR ) & 0xFF ) + 2 );

        if( ( SDIO_GetResponse( hsd->Instance, SDIO_RESP1 ) & SD_CARD_LOCKED ) == SD_CARD_LOCKED )
        {
            errorstate = SD_LOCK_UNLOCK_FAILED;

            return errorstate;
        }

        /* Get start and end block for high capacity cards */
        if( hsd->CardType == HIGH_CAPACITY_SD_CARD )
        {
            startaddr /= 512;
            endaddr /= 512;
        }

        /* According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */
        if( ( hsd->CardType == STD_CAPACITY_SD_CARD_V1_1 ) || ( hsd->CardType == STD_CAPACITY_SD_CARD_V2_0 ) || \
            ( hsd->CardType == HIGH_CAPACITY_SD_CARD ) )
        {
            /* Send CMD32 SD_ERASE_GRP_START with argument as addr  */
            sdmmc_cmdinitstructure.Argument = ( uint32_t ) startaddr;
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_ERASE_GRP_START;
            sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
            sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
            sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp1Error( hsd, SD_CMD_SD_ERASE_GRP_START );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            /* Send CMD33 SD_ERASE_GRP_END with argument as addr  */
            sdmmc_cmdinitstructure.Argument = ( uint32_t ) endaddr;
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_ERASE_GRP_END;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp1Error( hsd, SD_CMD_SD_ERASE_GRP_END );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }
        }

        /* Send CMD38 ERASE */
        sdmmc_cmdinitstructure.Argument = 0;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_ERASE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_ERASE );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        for( ; delay < maxdelay; delay++ )
        {
        }

        /* Wait until the card is in programming state */
        errorstate = SD_IsCardProgramming( hsd, &cardstate );

        delay = SD_DATATIMEOUT;

        while( ( delay > 0 ) && ( errorstate == SD_OK ) && ( ( cardstate == SD_CARD_PROGRAMMING ) || ( cardstate == SD_CARD_RECEIVING ) ) )
        {
            errorstate = SD_IsCardProgramming( hsd, &cardstate );
            delay--;
        }

        return errorstate;
    }

/**
 * @brief  This function handles SD card interrupt request.
 * @param  hsd SD handle
 * @retval None
 */
    void HAL_SD_IRQHandler( SD_HandleTypeDef * hsd )
    {
        /* Check for SDIO interrupt flags */
        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_IT_DATAEND ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_IT_DATAEND );

            /* SD transfer is complete */
            hsd->SdTransferCplt = 1;

            /* No transfer error */
            hsd->SdTransferErr = SD_OK;

            HAL_SD_XferCpltCallback( hsd );
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_IT_DCRCFAIL ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DCRCFAIL );

            hsd->SdTransferErr = SD_DATA_CRC_FAIL;

            HAL_SD_XferErrorCallback( hsd );
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_IT_DTIMEOUT ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DTIMEOUT );

            hsd->SdTransferErr = SD_DATA_TIMEOUT;

            HAL_SD_XferErrorCallback( hsd );
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_IT_RXOVERR ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_RXOVERR );

            hsd->SdTransferErr = SD_RX_OVERRUN;

            HAL_SD_XferErrorCallback( hsd );
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_IT_TXUNDERR ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_TXUNDERR );

            hsd->SdTransferErr = SD_TX_UNDERRUN;

            HAL_SD_XferErrorCallback( hsd );
        }
        else
        {
            /* No error flag set */
        }

        /* Disable all SDIO peripheral interrupt sources */
        __HAL_SD_SDIO_DISABLE_IT( hsd, SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | \
                                  SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |     \
                                  SDIO_IT_RXOVERR );
    }


/**
 * @brief  SD end of transfer callback.
 * @param  hsd SD handle
 * @retval None
 */
    __weak void HAL_SD_XferCpltCallback( SD_HandleTypeDef * hsd )
    {
        /* NOTE : This function Should not be modified, when the callback is needed,
         *        the HAL_SD_XferCpltCallback could be implemented in the user file
         */
    }

/**
 * @brief  SD Transfer Error callback.
 * @param  hsd SD handle
 * @retval None
 */
    __weak void HAL_SD_XferErrorCallback( SD_HandleTypeDef * hsd )
    {
        /* NOTE : This function Should not be modified, when the callback is needed,
         *        the HAL_SD_XferErrorCallback could be implemented in the user file
         */
    }

/**
 * @brief  SD Transfer complete Rx callback in non blocking mode.
 * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
 *                the configuration information for the specified DMA module.
 * @retval None
 */
    __weak void HAL_SD_DMA_RxCpltCallback( DMA_HandleTypeDef * hdma )
    {
        /* NOTE : This function Should not be modified, when the callback is needed,
         *        the HAL_SD_DMA_RxCpltCallback could be implemented in the user file
         */
    }

/**
 * @brief  SD DMA transfer complete Rx error callback.
 * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
 *                the configuration information for the specified DMA module.
 * @retval None
 */
    __weak void HAL_SD_DMA_RxErrorCallback( DMA_HandleTypeDef * hdma )
    {
        /* NOTE : This function Should not be modified, when the callback is needed,
         *        the HAL_SD_DMA_RxErrorCallback could be implemented in the user file
         */
    }

/**
 * @brief  SD Transfer complete Tx callback in non blocking mode.
 * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
 *                the configuration information for the specified DMA module.
 * @retval None
 */
    __weak void HAL_SD_DMA_TxCpltCallback( DMA_HandleTypeDef * hdma )
    {
        /* NOTE : This function Should not be modified, when the callback is needed,
         *        the HAL_SD_DMA_TxCpltCallback could be implemented in the user file
         */
    }

/**
 * @brief  SD DMA transfer complete error Tx callback.
 * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
 *                the configuration information for the specified DMA module.
 * @retval None
 */
    __weak void HAL_SD_DMA_TxErrorCallback( DMA_HandleTypeDef * hdma )
    {
        /* NOTE : This function Should not be modified, when the callback is needed,
         *        the HAL_SD_DMA_TxErrorCallback could be implemented in the user file
         */
    }

/**
 * @}
 */

/** @addtogroup SD_Exported_Functions_Group3
 *  @brief   management functions
 *
 * @verbatim
 * ==============================================================================
 ##### Peripheral Control functions #####
 #####==============================================================================
 #####[..]
 #####This subsection provides a set of functions allowing to control the SD card
 #####operations.
 #####
 #####@endverbatim
 * @{
 */

/**
 * @brief  Returns information about specific card.
 * @param  hsd SD handle
 * @param  pCardInfo Pointer to a HAL_SD_CardInfoTypedef structure that
 *         contains all SD cardinformation
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_Get_CardInfo( SD_HandleTypeDef * hsd,
                                             HAL_SD_CardInfoTypedef * pCardInfo )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t tmp = 0;

        pCardInfo->CardType = ( uint8_t ) ( hsd->CardType );
        pCardInfo->RCA = ( uint16_t ) ( hsd->RCA );

        /* Byte 0 */
        tmp = ( hsd->CSD[ 0 ] & 0xFF000000 ) >> 24;
        pCardInfo->SD_csd.CSDStruct = ( uint8_t ) ( ( tmp & 0xC0 ) >> 6 );
        pCardInfo->SD_csd.SysSpecVersion = ( uint8_t ) ( ( tmp & 0x3C ) >> 2 );
        pCardInfo->SD_csd.Reserved1 = tmp & 0x03;

        /* Byte 1 */
        tmp = ( hsd->CSD[ 0 ] & 0x00FF0000 ) >> 16;
        pCardInfo->SD_csd.TAAC = ( uint8_t ) tmp;

        /* Byte 2 */
        tmp = ( hsd->CSD[ 0 ] & 0x0000FF00 ) >> 8;
        pCardInfo->SD_csd.NSAC = ( uint8_t ) tmp;

        /* Byte 3 */
        tmp = hsd->CSD[ 0 ] & 0x000000FF;
        pCardInfo->SD_csd.MaxBusClkFrec = ( uint8_t ) tmp;

        /* Byte 4 */
        tmp = ( hsd->CSD[ 1 ] & 0xFF000000 ) >> 24;
        pCardInfo->SD_csd.CardComdClasses = ( uint16_t ) ( tmp << 4 );

        /* Byte 5 */
        tmp = ( hsd->CSD[ 1 ] & 0x00FF0000 ) >> 16;
        pCardInfo->SD_csd.CardComdClasses |= ( uint16_t ) ( ( tmp & 0xF0 ) >> 4 );
        pCardInfo->SD_csd.RdBlockLen = ( uint8_t ) ( tmp & 0x0F );

        /* Byte 6 */
        tmp = ( hsd->CSD[ 1 ] & 0x0000FF00 ) >> 8;
        pCardInfo->SD_csd.PartBlockRead = ( uint8_t ) ( ( tmp & 0x80 ) >> 7 );
        pCardInfo->SD_csd.WrBlockMisalign = ( uint8_t ) ( ( tmp & 0x40 ) >> 6 );
        pCardInfo->SD_csd.RdBlockMisalign = ( uint8_t ) ( ( tmp & 0x20 ) >> 5 );
        pCardInfo->SD_csd.DSRImpl = ( uint8_t ) ( ( tmp & 0x10 ) >> 4 );
        pCardInfo->SD_csd.Reserved2 = 0; /*!< Reserved */

        if( ( hsd->CardType == STD_CAPACITY_SD_CARD_V1_1 ) || ( hsd->CardType == STD_CAPACITY_SD_CARD_V2_0 ) )
        {
            pCardInfo->SD_csd.DeviceSize = ( tmp & 0x03 ) << 10;

            /* Byte 7 */
            tmp = ( uint8_t ) ( hsd->CSD[ 1 ] & 0x000000FF );
            pCardInfo->SD_csd.DeviceSize |= ( tmp ) << 2;

            /* Byte 8 */
            tmp = ( uint8_t ) ( ( hsd->CSD[ 2 ] & 0xFF000000 ) >> 24 );
            pCardInfo->SD_csd.DeviceSize |= ( tmp & 0xC0 ) >> 6;

            pCardInfo->SD_csd.MaxRdCurrentVDDMin = ( tmp & 0x38 ) >> 3;
            pCardInfo->SD_csd.MaxRdCurrentVDDMax = ( tmp & 0x07 );

            /* Byte 9 */
            tmp = ( uint8_t ) ( ( hsd->CSD[ 2 ] & 0x00FF0000 ) >> 16 );
            pCardInfo->SD_csd.MaxWrCurrentVDDMin = ( tmp & 0xE0 ) >> 5;
            pCardInfo->SD_csd.MaxWrCurrentVDDMax = ( tmp & 0x1C ) >> 2;
            pCardInfo->SD_csd.DeviceSizeMul = ( tmp & 0x03 ) << 1;
            /* Byte 10 */
            tmp = ( uint8_t ) ( ( hsd->CSD[ 2 ] & 0x0000FF00 ) >> 8 );
            pCardInfo->SD_csd.DeviceSizeMul |= ( tmp & 0x80 ) >> 7;

            pCardInfo->CardCapacity = ( pCardInfo->SD_csd.DeviceSize + 1 );
            pCardInfo->CardCapacity *= ( 1 << ( pCardInfo->SD_csd.DeviceSizeMul + 2 ) );
            pCardInfo->CardBlockSize = 1 << ( pCardInfo->SD_csd.RdBlockLen );
            pCardInfo->CardCapacity *= pCardInfo->CardBlockSize;
        }
        else if( hsd->CardType == HIGH_CAPACITY_SD_CARD )
        {
            /* Byte 7 */
            tmp = ( uint8_t ) ( hsd->CSD[ 1 ] & 0x000000FF );
            pCardInfo->SD_csd.DeviceSize = ( tmp & 0x3F ) << 16;

            /* Byte 8 */
            tmp = ( uint8_t ) ( ( hsd->CSD[ 2 ] & 0xFF000000 ) >> 24 );

            pCardInfo->SD_csd.DeviceSize |= ( tmp << 8 );

            /* Byte 9 */
            tmp = ( uint8_t ) ( ( hsd->CSD[ 2 ] & 0x00FF0000 ) >> 16 );

            pCardInfo->SD_csd.DeviceSize |= ( tmp );

            /* Byte 10 */
            tmp = ( uint8_t ) ( ( hsd->CSD[ 2 ] & 0x0000FF00 ) >> 8 );

            pCardInfo->CardCapacity = ( uint64_t ) ( ( ( ( uint64_t ) pCardInfo->SD_csd.DeviceSize + 1 ) ) * 512 * 1024 );
            pCardInfo->CardBlockSize = 512;
        }
        else
        {
            /* Not supported card type */
            errorstate = SD_ERROR;
        }

        pCardInfo->SD_csd.EraseGrSize = ( tmp & 0x40 ) >> 6;
        pCardInfo->SD_csd.EraseGrMul = ( tmp & 0x3F ) << 1;

        /* Byte 11 */
        tmp = ( uint8_t ) ( hsd->CSD[ 2 ] & 0x000000FF );
        pCardInfo->SD_csd.EraseGrMul |= ( tmp & 0x80 ) >> 7;
        pCardInfo->SD_csd.WrProtectGrSize = ( tmp & 0x7F );

        /* Byte 12 */
        tmp = ( uint8_t ) ( ( hsd->CSD[ 3 ] & 0xFF000000 ) >> 24 );
        pCardInfo->SD_csd.WrProtectGrEnable = ( tmp & 0x80 ) >> 7;
        pCardInfo->SD_csd.ManDeflECC = ( tmp & 0x60 ) >> 5;
        pCardInfo->SD_csd.WrSpeedFact = ( tmp & 0x1C ) >> 2;
        pCardInfo->SD_csd.MaxWrBlockLen = ( tmp & 0x03 ) << 2;

        /* Byte 13 */
        tmp = ( uint8_t ) ( ( hsd->CSD[ 3 ] & 0x00FF0000 ) >> 16 );
        pCardInfo->SD_csd.MaxWrBlockLen |= ( tmp & 0xC0 ) >> 6;
        pCardInfo->SD_csd.WriteBlockPaPartial = ( tmp & 0x20 ) >> 5;
        pCardInfo->SD_csd.Reserved3 = 0;
        pCardInfo->SD_csd.ContentProtectAppli = ( tmp & 0x01 );

        /* Byte 14 */
        tmp = ( uint8_t ) ( ( hsd->CSD[ 3 ] & 0x0000FF00 ) >> 8 );
        pCardInfo->SD_csd.FileFormatGroup = ( tmp & 0x80 ) >> 7;
        pCardInfo->SD_csd.CopyFlag = ( tmp & 0x40 ) >> 6;
        pCardInfo->SD_csd.PermWrProtect = ( tmp & 0x20 ) >> 5;
        pCardInfo->SD_csd.TempWrProtect = ( tmp & 0x10 ) >> 4;
        pCardInfo->SD_csd.FileFormat = ( tmp & 0x0C ) >> 2;
        pCardInfo->SD_csd.ECC = ( tmp & 0x03 );

        /* Byte 15 */
        tmp = ( uint8_t ) ( hsd->CSD[ 3 ] & 0x000000FF );
        pCardInfo->SD_csd.CSD_CRC = ( tmp & 0xFE ) >> 1;
        pCardInfo->SD_csd.Reserved4 = 1;

        /* Byte 0 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 0 ] & 0xFF000000 ) >> 24 );
        pCardInfo->SD_cid.ManufacturerID = tmp;

        /* Byte 1 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 0 ] & 0x00FF0000 ) >> 16 );
        pCardInfo->SD_cid.OEM_AppliID = tmp << 8;

        /* Byte 2 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 0 ] & 0x000000FF00 ) >> 8 );
        pCardInfo->SD_cid.OEM_AppliID |= tmp;

        /* Byte 3 */
        tmp = ( uint8_t ) ( hsd->CID[ 0 ] & 0x000000FF );
        pCardInfo->SD_cid.ProdName1 = tmp << 24;

        /* Byte 4 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 1 ] & 0xFF000000 ) >> 24 );
        pCardInfo->SD_cid.ProdName1 |= tmp << 16;

        /* Byte 5 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 1 ] & 0x00FF0000 ) >> 16 );
        pCardInfo->SD_cid.ProdName1 |= tmp << 8;

        /* Byte 6 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 1 ] & 0x0000FF00 ) >> 8 );
        pCardInfo->SD_cid.ProdName1 |= tmp;

        /* Byte 7 */
        tmp = ( uint8_t ) ( hsd->CID[ 1 ] & 0x000000FF );
        pCardInfo->SD_cid.ProdName2 = tmp;

        /* Byte 8 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 2 ] & 0xFF000000 ) >> 24 );
        pCardInfo->SD_cid.ProdRev = tmp;

        /* Byte 9 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 2 ] & 0x00FF0000 ) >> 16 );
        pCardInfo->SD_cid.ProdSN = tmp << 24;

        /* Byte 10 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 2 ] & 0x0000FF00 ) >> 8 );
        pCardInfo->SD_cid.ProdSN |= tmp << 16;

        /* Byte 11 */
        tmp = ( uint8_t ) ( hsd->CID[ 2 ] & 0x000000FF );
        pCardInfo->SD_cid.ProdSN |= tmp << 8;

        /* Byte 12 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 3 ] & 0xFF000000 ) >> 24 );
        pCardInfo->SD_cid.ProdSN |= tmp;

        /* Byte 13 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 3 ] & 0x00FF0000 ) >> 16 );
        pCardInfo->SD_cid.Reserved1 |= ( tmp & 0xF0 ) >> 4;
        pCardInfo->SD_cid.ManufactDate = ( tmp & 0x0F ) << 8;

        /* Byte 14 */
        tmp = ( uint8_t ) ( ( hsd->CID[ 3 ] & 0x0000FF00 ) >> 8 );
        pCardInfo->SD_cid.ManufactDate |= tmp;

        /* Byte 15 */
        tmp = ( uint8_t ) ( hsd->CID[ 3 ] & 0x000000FF );
        pCardInfo->SD_cid.CID_CRC = ( tmp & 0xFE ) >> 1;
        pCardInfo->SD_cid.Reserved2 = 1;

        return errorstate;
    }

/**
 * @brief  Enables wide bus operation for the requested card if supported by
 *         card.
 * @param  hsd SD handle
 * @param  WideMode Specifies the SD card wide bus mode
 *          This parameter can be one of the following values:
 *            @arg SDIO_BUS_WIDE_8B: 8-bit data transfer (Only for MMC)
 *            @arg SDIO_BUS_WIDE_4B: 4-bit data transfer
 *            @arg SDIO_BUS_WIDE_1B: 1-bit data transfer
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_WideBusOperation_Config( SD_HandleTypeDef * hsd,
                                                        uint32_t WideMode )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        SDIO_InitTypeDef tmpinit;

        /* MMC Card does not support this feature */
        if( hsd->CardType == MULTIMEDIA_CARD )
        {
            errorstate = SD_UNSUPPORTED_FEATURE;

            return errorstate;
        }
        else if( ( hsd->CardType == STD_CAPACITY_SD_CARD_V1_1 ) || ( hsd->CardType == STD_CAPACITY_SD_CARD_V2_0 ) || \
                 ( hsd->CardType == HIGH_CAPACITY_SD_CARD ) )
        {
            if( WideMode == SDIO_BUS_WIDE_8B )
            {
                errorstate = SD_UNSUPPORTED_FEATURE;
            }
            else if( WideMode == SDIO_BUS_WIDE_4B )
            {
                errorstate = SD_WideBus_Enable( hsd );
            }
            else if( WideMode == SDIO_BUS_WIDE_1B )
            {
                errorstate = SD_WideBus_Disable( hsd );
            }
            else
            {
                /* WideMode is not a valid argument*/
                errorstate = SD_INVALID_PARAMETER;
            }

            if( errorstate == SD_OK )
            {
                /* Configure the SDIO peripheral */
                tmpinit.ClockEdge = hsd->Init.ClockEdge;
                tmpinit.ClockBypass = hsd->Init.ClockBypass;
                tmpinit.ClockPowerSave = hsd->Init.ClockPowerSave;
                tmpinit.BusWide = WideMode;
                tmpinit.HardwareFlowControl = hsd->Init.HardwareFlowControl;
                tmpinit.ClockDiv = hsd->Init.ClockDiv;
                SDIO_Init( hsd->Instance, tmpinit );
            }
        }

        return errorstate;
    }

/**
 * @brief  Aborts an ongoing data transfer.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_StopTransfer( SD_HandleTypeDef * hsd )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;

        /* Send CMD12 STOP_TRANSMISSION  */
        sdmmc_cmdinitstructure.Argument = 0;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_STOP_TRANSMISSION;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_STOP_TRANSMISSION );

        return errorstate;
    }

/**
 * @brief  Switches the SD card to High Speed mode.
 *         This API must be used after "Transfer State"
 * @note   This operation should be followed by the configuration
 *         of PLL to have SDIOCK clock between 67 and 75 MHz
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_HighSpeed( SD_HandleTypeDef * hsd )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        SDIO_DataInitTypeDef sdmmc_datainitstructure;

        uint8_t SD_hs[ 64 ] = { 0 };
        uint32_t SD_scr[ 2 ] = { 0, 0 };
        uint32_t SD_SPEC = 0;
        uint32_t count = 0, * tempbuff = ( uint32_t * ) SD_hs;

        /* Initialize the Data control register */
        hsd->Instance->DCTRL = 0;

        /* Get SCR Register */
        errorstate = SD_FindSCR( hsd, SD_scr );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Test the Version supported by the card*/
        SD_SPEC = ( SD_scr[ 1 ] & 0x01000000 ) | ( SD_scr[ 1 ] & 0x02000000 );

        if( SD_SPEC != SD_ALLZERO )
        {
            /* Set Block Size for Card */
            sdmmc_cmdinitstructure.Argument = ( uint32_t ) 64;
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
            sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
            sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
            sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp1Error( hsd, SD_CMD_SET_BLOCKLEN );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            /* Configure the SD DPSM (Data Path State Machine) */
            sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT;
            sdmmc_datainitstructure.DataLength = 64;
            sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_64B;
            sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
            sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
            sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE;
            SDIO_DataConfig( hsd->Instance, &sdmmc_datainitstructure );

            /* Send CMD6 switch mode */
            sdmmc_cmdinitstructure.Argument = 0x80FFFF01;
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_HS_SWITCH;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp1Error( hsd, SD_CMD_HS_SWITCH );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND ) )
            {
                if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXFIFOHF ) )
                {
                    for( count = 0; count < 8; count++ )
                    {
                        *( tempbuff + count ) = SDIO_ReadFIFO( hsd->Instance );
                    }

                    tempbuff += 8;
                }
            }

            if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DTIMEOUT ) )
            {
                __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DTIMEOUT );

                errorstate = SD_DATA_TIMEOUT;

                return errorstate;
            }
            else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DCRCFAIL ) )
            {
                __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DCRCFAIL );

                errorstate = SD_DATA_CRC_FAIL;

                return errorstate;
            }
            else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR ) )
            {
                __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_RXOVERR );

                errorstate = SD_RX_OVERRUN;

                return errorstate;
            }
            else
            {
                /* No error flag set */
            }

            count = SD_DATATIMEOUT;

            while( ( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXDAVL ) ) && ( count > 0 ) )
            {
                *tempbuff = SDIO_ReadFIFO( hsd->Instance );
                tempbuff++;
                count--;
            }

            /* Clear all the static flags */
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

            /* Test if the switch mode HS is ok */
            if( ( SD_hs[ 13 ] & 2 ) != 2 )
            {
                errorstate = SD_UNSUPPORTED_FEATURE;
            }
        }

        return errorstate;
    }

/**
 * @}
 */

/** @addtogroup SD_Exported_Functions_Group4
 *  @brief   Peripheral State functions
 *
 * @verbatim
 * ==============================================================================
 ##### Peripheral State functions #####
 #####==============================================================================
 #####[..]
 #####This subsection permits to get in runtime the status of the peripheral
 #####and the data flow.
 #####
 #####@endverbatim
 * @{
 */

/**
 * @brief  Returns the current SD card's status.
 * @param  hsd SD handle
 * @param  pSDstatus Pointer to the buffer that will contain the SD card status
 *         SD Status register)
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_SendSDStatus( SD_HandleTypeDef * hsd,
                                             uint32_t * pSDstatus )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        SDIO_DataInitTypeDef sdmmc_datainitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t count = 0;

        /* Check SD response */
        if( ( SDIO_GetResponse( hsd->Instance, SDIO_RESP1 ) & SD_CARD_LOCKED ) == SD_CARD_LOCKED )
        {
            errorstate = SD_LOCK_UNLOCK_FAILED;

            return errorstate;
        }

        /* Set block size for card if it is not equal to current block size for card */
        sdmmc_cmdinitstructure.Argument = 64;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SET_BLOCKLEN );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Send CMD55 */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) ( hsd->RCA << 16 );
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_APP_CMD );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Configure the SD DPSM (Data Path State Machine) */
        sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT;
        sdmmc_datainitstructure.DataLength = 64;
        sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_64B;
        sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
        sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
        sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE;
        SDIO_DataConfig( hsd->Instance, &sdmmc_datainitstructure );

        /* Send ACMD13 (SD_APP_STATUS)  with argument as card's RCA */
        sdmmc_cmdinitstructure.Argument = 0;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_STATUS;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SD_APP_STATUS );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Get status data */
        while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND ) )
        {
            if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXFIFOHF ) )
            {
                for( count = 0; count < 8; count++ )
                {
                    *( pSDstatus + count ) = SDIO_ReadFIFO( hsd->Instance );
                }

                pSDstatus += 8;
            }
        }

        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DTIMEOUT ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DTIMEOUT );

            errorstate = SD_DATA_TIMEOUT;

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DCRCFAIL ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DCRCFAIL );

            errorstate = SD_DATA_CRC_FAIL;

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_RXOVERR );

            errorstate = SD_RX_OVERRUN;

            return errorstate;
        }
        else
        {
            /* No error flag set */
        }

        count = SD_DATATIMEOUT;

        while( ( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXDAVL ) ) && ( count > 0 ) )
        {
            *pSDstatus = SDIO_ReadFIFO( hsd->Instance );
            pSDstatus++;
            count--;
        }

        /* Clear all the static status flags*/
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        return errorstate;
    }

/**
 * @brief  Gets the current sd card data status.
 * @param  hsd SD handle
 * @retval Data Transfer state
 */
    HAL_SD_TransferStateTypedef HAL_SD_GetStatus( SD_HandleTypeDef * hsd )
    {
        HAL_SD_CardStateTypedef cardstate = SD_CARD_TRANSFER;

        /* Get SD card state */
        cardstate = SD_GetState( hsd );

        /* Find SD status according to card state*/
        if( cardstate == SD_CARD_TRANSFER )
        {
            return SD_TRANSFER_OK;
        }
        else if( cardstate == SD_CARD_ERROR )
        {
            return SD_TRANSFER_ERROR;
        }
        else
        {
            return SD_TRANSFER_BUSY;
        }
    }

/**
 * @brief  Gets the SD card status.
 * @param  hsd SD handle
 * @param  pCardStatus Pointer to the HAL_SD_CardStatusTypedef structure that
 *         will contain the SD card status information
 * @retval SD Card error state
 */
    HAL_SD_ErrorTypedef HAL_SD_GetCardStatus( SD_HandleTypeDef * hsd,
                                              HAL_SD_CardStatusTypedef * pCardStatus )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t tmp = 0;
        uint32_t sd_status[ 16 ];

        errorstate = HAL_SD_SendSDStatus( hsd, sd_status );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Byte 0 */
        tmp = ( sd_status[ 0 ] & 0xC0 ) >> 6;
        pCardStatus->DAT_BUS_WIDTH = ( uint8_t ) tmp;

        /* Byte 0 */
        tmp = ( sd_status[ 0 ] & 0x20 ) >> 5;
        pCardStatus->SECURED_MODE = ( uint8_t ) tmp;

        /* Byte 2 */
        tmp = ( sd_status[ 2 ] & 0xFF );
        pCardStatus->SD_CARD_TYPE = ( uint8_t ) ( tmp << 8 );

        /* Byte 3 */
        tmp = ( sd_status[ 3 ] & 0xFF );
        pCardStatus->SD_CARD_TYPE |= ( uint8_t ) tmp;

        /* Byte 4 */
        tmp = ( sd_status[ 4 ] & 0xFF );
        pCardStatus->SIZE_OF_PROTECTED_AREA = ( uint8_t ) ( tmp << 24 );

        /* Byte 5 */
        tmp = ( sd_status[ 5 ] & 0xFF );
        pCardStatus->SIZE_OF_PROTECTED_AREA |= ( uint8_t ) ( tmp << 16 );

        /* Byte 6 */
        tmp = ( sd_status[ 6 ] & 0xFF );
        pCardStatus->SIZE_OF_PROTECTED_AREA |= ( uint8_t ) ( tmp << 8 );

        /* Byte 7 */
        tmp = ( sd_status[ 7 ] & 0xFF );
        pCardStatus->SIZE_OF_PROTECTED_AREA |= ( uint8_t ) tmp;

        /* Byte 8 */
        tmp = ( sd_status[ 8 ] & 0xFF );
        pCardStatus->SPEED_CLASS = ( uint8_t ) tmp;

        /* Byte 9 */
        tmp = ( sd_status[ 9 ] & 0xFF );
        pCardStatus->PERFORMANCE_MOVE = ( uint8_t ) tmp;

        /* Byte 10 */
        tmp = ( sd_status[ 10 ] & 0xF0 ) >> 4;
        pCardStatus->AU_SIZE = ( uint8_t ) tmp;

        /* Byte 11 */
        tmp = ( sd_status[ 11 ] & 0xFF );
        pCardStatus->ERASE_SIZE = ( uint8_t ) ( tmp << 8 );

        /* Byte 12 */
        tmp = ( sd_status[ 12 ] & 0xFF );
        pCardStatus->ERASE_SIZE |= ( uint8_t ) tmp;

        /* Byte 13 */
        tmp = ( sd_status[ 13 ] & 0xFC ) >> 2;
        pCardStatus->ERASE_TIMEOUT = ( uint8_t ) tmp;

        /* Byte 13 */
        tmp = ( sd_status[ 13 ] & 0x3 );
        pCardStatus->ERASE_OFFSET = ( uint8_t ) tmp;

        return errorstate;
    }

/**
 * @}
 */

/**
 * @}
 */

/* Private function ----------------------------------------------------------*/

/** @addtogroup SD_Private_Functions
 * @{
 */

/**
 * @brief  SD DMA transfer complete Rx callback.
 * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
 *                the configuration information for the specified DMA module.
 * @retval None
 */
    static void SD_DMA_RxCplt( DMA_HandleTypeDef * hdma )
    {
        SD_HandleTypeDef * hsd = ( SD_HandleTypeDef * ) ( ( DMA_HandleTypeDef * ) hdma )->Parent;

        /* DMA transfer is complete */
        hsd->DmaTransferCplt = 1;

/*  / * Wait until SD transfer is complete * / */
/*  while(hsd->SdTransferCplt == 0) */
/*  { */
/*  } */
/* */
/*  / * Disable the DMA channel * / */
/*  HAL_DMA_Abort(hdma); */

        /* Transfer complete user callback */
        HAL_SD_DMA_RxCpltCallback( hsd->hdmarx );
    }

/**
 * @brief  SD DMA transfer Error Rx callback.
 * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
 *                the configuration information for the specified DMA module.
 * @retval None
 */
    static void SD_DMA_RxError( DMA_HandleTypeDef * hdma )
    {
        SD_HandleTypeDef * hsd = ( SD_HandleTypeDef * ) ( ( DMA_HandleTypeDef * ) hdma )->Parent;

        /* Transfer complete user callback */
        HAL_SD_DMA_RxErrorCallback( hsd->hdmarx );
    }

/**
 * @brief  SD DMA transfer complete Tx callback.
 * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
 *                the configuration information for the specified DMA module.
 * @retval None
 */
    static void SD_DMA_TxCplt( DMA_HandleTypeDef * hdma )
    {
        SD_HandleTypeDef * hsd = ( SD_HandleTypeDef * ) ( ( DMA_HandleTypeDef * ) hdma )->Parent;

        /* DMA transfer is complete */
        hsd->DmaTransferCplt = 1;

/*  / * Wait until SD transfer is complete * / */
/*  while(hsd->SdTransferCplt == 0) */
/*  { */
/*  } */
/* */
/*  / * Disable the DMA channel * / */
/*  HAL_DMA_Abort(hdma); */

        /* Transfer complete user callback */
        HAL_SD_DMA_TxCpltCallback( hsd->hdmatx );
    }

/**
 * @brief  SD DMA transfer Error Tx callback.
 * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
 *                the configuration information for the specified DMA module.
 * @retval None
 */
    static void SD_DMA_TxError( DMA_HandleTypeDef * hdma )
    {
        SD_HandleTypeDef * hsd = ( SD_HandleTypeDef * ) ( ( DMA_HandleTypeDef * ) hdma )->Parent;

        /* Transfer complete user callback */
        HAL_SD_DMA_TxErrorCallback( hsd->hdmatx );
    }

/**
 * @brief  Returns the SD current state.
 * @param  hsd SD handle
 * @retval SD card current state
 */
    static HAL_SD_CardStateTypedef SD_GetState( SD_HandleTypeDef * hsd )
    {
        uint32_t resp1 = 0;

        if( SD_SendStatus( hsd, &resp1 ) != SD_OK )
        {
            return SD_CARD_ERROR;
        }
        else
        {
            return ( HAL_SD_CardStateTypedef ) ( ( resp1 >> 9 ) & 0x0F );
        }
    }

/**
 * @brief  Initializes all cards or single card as the case may be Card(s) come
 *         into standby state.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_Initialize_Cards( SD_HandleTypeDef * hsd )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint16_t sd_rca = 1;

        if( SDIO_GetPowerState( hsd->Instance ) == 0 ) /* Power off */
        {
            errorstate = SD_REQUEST_NOT_APPLICABLE;

            return errorstate;
        }

        if( hsd->CardType != SECURE_DIGITAL_IO_CARD )
        {
            /* Send CMD2 ALL_SEND_CID */
            sdmmc_cmdinitstructure.Argument = 0;
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_ALL_SEND_CID;
            sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_LONG;
            sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
            sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp2Error( hsd );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            /* Get Card identification number data */
            hsd->CID[ 0 ] = SDIO_GetResponse( hsd->Instance, SDIO_RESP1 );
            hsd->CID[ 1 ] = SDIO_GetResponse( hsd->Instance, SDIO_RESP2 );
            hsd->CID[ 2 ] = SDIO_GetResponse( hsd->Instance, SDIO_RESP3 );
            hsd->CID[ 3 ] = SDIO_GetResponse( hsd->Instance, SDIO_RESP4 );
        }

        if( ( hsd->CardType == STD_CAPACITY_SD_CARD_V1_1 ) || ( hsd->CardType == STD_CAPACITY_SD_CARD_V2_0 ) || \
            ( hsd->CardType == SECURE_DIGITAL_IO_COMBO_CARD ) || ( hsd->CardType == HIGH_CAPACITY_SD_CARD ) )
        {
            /* Send CMD3 SET_REL_ADDR with argument 0 */
            /* SD Card publishes its RCA. */
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_REL_ADDR;
            sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp6Error( hsd, SD_CMD_SET_REL_ADDR, &sd_rca );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }
        }

        if( hsd->CardType != SECURE_DIGITAL_IO_CARD )
        {
            /* Get the SD card RCA */
            hsd->RCA = sd_rca;

            /* Send CMD9 SEND_CSD with argument as card's RCA */
            sdmmc_cmdinitstructure.Argument = ( uint32_t ) ( hsd->RCA << 16 );
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_CSD;
            sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_LONG;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp2Error( hsd );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            /* Get Card Specific Data */
            hsd->CSD[ 0 ] = SDIO_GetResponse( hsd->Instance, SDIO_RESP1 );
            hsd->CSD[ 1 ] = SDIO_GetResponse( hsd->Instance, SDIO_RESP2 );
            hsd->CSD[ 2 ] = SDIO_GetResponse( hsd->Instance, SDIO_RESP3 );
            hsd->CSD[ 3 ] = SDIO_GetResponse( hsd->Instance, SDIO_RESP4 );
        }

        /* All cards are initialized */
        return errorstate;
    }

/**
 * @brief  Selects of Deselects the corresponding card.
 * @param  hsd SD handle
 * @param  addr Address of the card to be selected
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_Select_Deselect( SD_HandleTypeDef * hsd,
                                                   uint64_t addr )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;

        /* Send CMD7 SDIO_SEL_DESEL_CARD */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) addr;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEL_DESEL_CARD;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SEL_DESEL_CARD );

        return errorstate;
    }

/**
 * @brief  Enquires cards about their operating voltage and configures clock
 *         controls and stores SD information that will be needed in future
 *         in the SD handle.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_PowerON( SD_HandleTypeDef * hsd )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        __IO HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t response = 0, count = 0, validvoltage = 0;
        uint32_t sdtype = SD_STD_CAPACITY;

        /* Power ON Sequence -------------------------------------------------------*/
        /* Disable SDMMC Clock */
        __HAL_SD_SDIO_DISABLE( hsd );

        /* Set Power State to ON */
        SDIO_PowerState_ON( hsd->Instance );

        /* 1ms: required power up waiting time before starting the SD initialization
         * sequence */
        HAL_Delay( 1 );

        /* Enable SDMMC Clock */
        __HAL_SD_SDIO_ENABLE( hsd );

        /* CMD0: GO_IDLE_STATE -----------------------------------------------------*/
        /* No CMD response required */
        sdmmc_cmdinitstructure.Argument = 0;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_GO_IDLE_STATE;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_NO;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdError( hsd );

        if( errorstate != SD_OK )
        {
            /* CMD Response Timeout (wait for CMDSENT flag) */
            return errorstate;
        }

        /* CMD8: SEND_IF_COND ------------------------------------------------------*/
        /* Send CMD8 to verify SD card interface operating condition */

        /* Argument: - [31:12]: Reserved (shall be set to '0')
         * - [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
         * - [7:0]: Check Pattern (recommended 0xAA) */
        /* CMD Response: R7 */
        sdmmc_cmdinitstructure.Argument = SD_CHECK_PATTERN;
        sdmmc_cmdinitstructure.CmdIndex = SD_SDIO_SEND_IF_COND;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp7Error( hsd );

        if( errorstate == SD_OK )
        {
            /* SD Card 2.0 */
            FF_PRINTF( "It's a 2.0 card, check SDHC\n" );
            hsd->CardType = STD_CAPACITY_SD_CARD_V2_0;
            sdtype = SD_HIGH_CAPACITY;
        }

        /* Send CMD55 */
        sdmmc_cmdinitstructure.Argument = 0;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_APP_CMD );

        /* If errorstate is Command Timeout, it is a MMC card */

        /* If errorstate is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch)
         * or SD card 1.x */
        if( errorstate == SD_OK )
        {
            /* SD CARD */
            /* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */
            while( ( !validvoltage ) && ( count < SD_MAX_VOLT_TRIAL ) )
            {
                /* SEND CMD55 APP_CMD with RCA as 0 */
                sdmmc_cmdinitstructure.Argument = 0;
                sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD;
                sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
                sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
                sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
                SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

                /* Check for error conditions */
                errorstate = SD_CmdResp1Error( hsd, SD_CMD_APP_CMD );

                if( errorstate != SD_OK )
                {
                    return errorstate;
                }

                /* Send CMD41 */
                sdmmc_cmdinitstructure.Argument = SD_VOLTAGE_WINDOW_SD | sdtype;
                sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_OP_COND;
                sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
                sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
                sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
                SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

                /* Check for error conditions */
                errorstate = SD_CmdResp3Error( hsd );

                if( errorstate != SD_OK )
                {
                    return errorstate;
                }

                /* Get command response */
                response = SDIO_GetResponse( hsd->Instance, SDIO_RESP1 );

                /* Get operating voltage*/
                validvoltage = ( ( ( response >> 31 ) == 1 ) ? 1 : 0 );

                if( ( count == 0 ) || ( validvoltage != 0 ) )
                {
                    FF_PRINTF( "Voltage resp: %08x\n", response );
                }

                count++;
            }

            if( count >= SD_MAX_VOLT_TRIAL )
            {
                FF_PRINTF( "Can not agree on Voltage\n" );
                errorstate = SD_INVALID_VOLTRANGE;

                return errorstate;
            }

            if( ( response & SD_HIGH_CAPACITY ) == SD_HIGH_CAPACITY ) /* (response &= SD_HIGH_CAPACITY) */
            {
                hsd->CardType = HIGH_CAPACITY_SD_CARD;
            }
        } /* else MMC Card */

        return errorstate;
    }

/**
 * @brief  Turns the SDMMC output signals off.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_PowerOFF( SD_HandleTypeDef * hsd )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;

        /* Set Power State to OFF */
        SDIO_PowerState_OFF( hsd->Instance );

        return errorstate;
    }

/**
 * @brief  Returns the current card's status.
 * @param  hsd SD handle
 * @param  pCardStatus pointer to the buffer that will contain the SD card
 *         status (Card Status register)
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_SendStatus( SD_HandleTypeDef * hsd,
                                              uint32_t * pCardStatus )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;

        if( pCardStatus == NULL )
        {
            errorstate = SD_INVALID_PARAMETER;

            return errorstate;
        }

        /* Send Status command */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) ( hsd->RCA << 16 );
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_STATUS;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SEND_STATUS );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Get SD card status */
        *pCardStatus = SDIO_GetResponse( hsd->Instance, SDIO_RESP1 );

        return errorstate;
    }

/**
 * @brief  Checks for error conditions for CMD0.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_CmdError( SD_HandleTypeDef * hsd )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
/*  uint32_t timeout; */
        uint32_t tmp;
        uint32_t ulStarted = xTaskGetTickCount();
        uint32_t ulMaxTime = 200;
        BaseType_t xHadTimeout = pdFALSE;

/*  timeout = SDIO_CMD0TIMEOUT; */

        tmp = __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CMDSENT );

        while( tmp == 0 )
        {
            tmp = __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CMDSENT );

            if( ( xTaskGetTickCount() - ulStarted ) >= ulMaxTime )
            {
                xHadTimeout = pdTRUE;
                break;
            }
        }

        if( xHadTimeout != pdFALSE )
        {
            errorstate = SD_CMD_RSP_TIMEOUT;
            return errorstate;
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        return errorstate;
    }

/**
 * @brief  Checks for error conditions for R7 response.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_CmdResp7Error( SD_HandleTypeDef * hsd )
    {
        HAL_SD_ErrorTypedef errorstate = SD_ERROR;
/*  uint32_t timeout = SDIO_CMD0TIMEOUT; */
        uint32_t tmp;
        uint32_t ulStarted = xTaskGetTickCount();
        uint32_t ulMaxTime = 200;
        BaseType_t xHadTimeout = pdFALSE;

        tmp = __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT );

        while( tmp == 0 )
        {
            tmp = __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT );

            if( ( xTaskGetTickCount() - ulStarted ) >= ulMaxTime )
            {
                xHadTimeout = pdTRUE;
                break;
            }
        }

        tmp = __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CTIMEOUT );

        if( ( xHadTimeout != pdFALSE ) || tmp )
        {
            /* Card is not V2.0 compliant or card does not support the set voltage range */
            errorstate = SD_CMD_RSP_TIMEOUT;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CTIMEOUT );

            return errorstate;
        }

        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CMDREND ) )
        {
            /* Card is SD V2.0 compliant */
            errorstate = SD_OK;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CMDREND );

            return errorstate;
        }

        return errorstate;
    }

/**
 * @brief  Checks for error conditions for R1 response.
 * @param  hsd SD handle
 * @param  SD_CMD The sent command index
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_CmdResp1Error( SD_HandleTypeDef * hsd,
                                                 uint8_t SD_CMD )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t response_r1;
        uint32_t remaining_loops = 168000 * 50;

        while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT ) )
        {
            if( ( --remaining_loops ) == 0 )
            {
                FF_PRINTF( "SD_CmdResp1Error: times out\n" );
                break;
            }
        }

        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CTIMEOUT ) )
        {
            errorstate = SD_CMD_RSP_TIMEOUT;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CTIMEOUT );

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL ) )
        {
            errorstate = SD_CMD_CRC_FAIL;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CCRCFAIL );

            return errorstate;
        }

        /* Check response received is of desired command */
        if( SDIO_GetCommandResponse( hsd->Instance ) != SD_CMD )
        {
            errorstate = SD_ILLEGAL_CMD;

            return errorstate;
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        /* We have received response, retrieve it for analysis  */
        response_r1 = SDIO_GetResponse( hsd->Instance, SDIO_RESP1 );

        if( ( response_r1 & SD_OCR_ERRORBITS ) == SD_ALLZERO )
        {
            return errorstate;
        }

        if( ( response_r1 & SD_OCR_ADDR_OUT_OF_RANGE ) == SD_OCR_ADDR_OUT_OF_RANGE )
        {
            return( SD_ADDR_OUT_OF_RANGE );
        }

        if( ( response_r1 & SD_OCR_ADDR_MISALIGNED ) == SD_OCR_ADDR_MISALIGNED )
        {
            return( SD_ADDR_MISALIGNED );
        }

        if( ( response_r1 & SD_OCR_BLOCK_LEN_ERR ) == SD_OCR_BLOCK_LEN_ERR )
        {
            return( SD_BLOCK_LEN_ERR );
        }

        if( ( response_r1 & SD_OCR_ERASE_SEQ_ERR ) == SD_OCR_ERASE_SEQ_ERR )
        {
            return( SD_ERASE_SEQ_ERR );
        }

        if( ( response_r1 & SD_OCR_BAD_ERASE_PARAM ) == SD_OCR_BAD_ERASE_PARAM )
        {
            return( SD_BAD_ERASE_PARAM );
        }

        if( ( response_r1 & SD_OCR_WRITE_PROT_VIOLATION ) == SD_OCR_WRITE_PROT_VIOLATION )
        {
            return( SD_WRITE_PROT_VIOLATION );
        }

        if( ( response_r1 & SD_OCR_LOCK_UNLOCK_FAILED ) == SD_OCR_LOCK_UNLOCK_FAILED )
        {
            return( SD_LOCK_UNLOCK_FAILED );
        }

        if( ( response_r1 & SD_OCR_COM_CRC_FAILED ) == SD_OCR_COM_CRC_FAILED )
        {
            return( SD_COM_CRC_FAILED );
        }

        if( ( response_r1 & SD_OCR_ILLEGAL_CMD ) == SD_OCR_ILLEGAL_CMD )
        {
            return( SD_ILLEGAL_CMD );
        }

        if( ( response_r1 & SD_OCR_CARD_ECC_FAILED ) == SD_OCR_CARD_ECC_FAILED )
        {
            return( SD_CARD_ECC_FAILED );
        }

        if( ( response_r1 & SD_OCR_CC_ERROR ) == SD_OCR_CC_ERROR )
        {
            return( SD_CC_ERROR );
        }

        if( ( response_r1 & SD_OCR_GENERAL_UNKNOWN_ERROR ) == SD_OCR_GENERAL_UNKNOWN_ERROR )
        {
            return( SD_GENERAL_UNKNOWN_ERROR );
        }

        if( ( response_r1 & SD_OCR_STREAM_READ_UNDERRUN ) == SD_OCR_STREAM_READ_UNDERRUN )
        {
            return( SD_STREAM_READ_UNDERRUN );
        }

        if( ( response_r1 & SD_OCR_STREAM_WRITE_OVERRUN ) == SD_OCR_STREAM_WRITE_OVERRUN )
        {
            return( SD_STREAM_WRITE_OVERRUN );
        }

        if( ( response_r1 & SD_OCR_CID_CSD_OVERWRITE ) == SD_OCR_CID_CSD_OVERWRITE )
        {
            return( SD_CID_CSD_OVERWRITE );
        }

        if( ( response_r1 & SD_OCR_WP_ERASE_SKIP ) == SD_OCR_WP_ERASE_SKIP )
        {
            return( SD_WP_ERASE_SKIP );
        }

        if( ( response_r1 & SD_OCR_CARD_ECC_DISABLED ) == SD_OCR_CARD_ECC_DISABLED )
        {
            return( SD_CARD_ECC_DISABLED );
        }

        if( ( response_r1 & SD_OCR_ERASE_RESET ) == SD_OCR_ERASE_RESET )
        {
            return( SD_ERASE_RESET );
        }

        if( ( response_r1 & SD_OCR_AKE_SEQ_ERROR ) == SD_OCR_AKE_SEQ_ERROR )
        {
            return( SD_AKE_SEQ_ERROR );
        }

        return errorstate;
    }

/**
 * @brief  Checks for error conditions for R3 (OCR) response.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_CmdResp3Error( SD_HandleTypeDef * hsd )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;

        while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT ) )
        {
        }

        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CTIMEOUT ) )
        {
            errorstate = SD_CMD_RSP_TIMEOUT;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CTIMEOUT );

            return errorstate;
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        return errorstate;
    }

/**
 * @brief  Checks for error conditions for R2 (CID or CSD) response.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_CmdResp2Error( SD_HandleTypeDef * hsd )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;

        while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT ) )
        {
        }

        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CTIMEOUT ) )
        {
            errorstate = SD_CMD_RSP_TIMEOUT;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CTIMEOUT );

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL ) )
        {
            errorstate = SD_CMD_CRC_FAIL;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CCRCFAIL );

            return errorstate;
        }
        else
        {
            /* No error flag set */
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        return errorstate;
    }

/**
 * @brief  Checks for error conditions for R6 (RCA) response.
 * @param  hsd SD handle
 * @param  SD_CMD The sent command index
 * @param  pRCA Pointer to the variable that will contain the SD card relative
 *         address RCA
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_CmdResp6Error( SD_HandleTypeDef * hsd,
                                                 uint8_t SD_CMD,
                                                 uint16_t * pRCA )
    {
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t response_r1;

        while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT ) )
        {
        }

        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CTIMEOUT ) )
        {
            errorstate = SD_CMD_RSP_TIMEOUT;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CTIMEOUT );

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL ) )
        {
            errorstate = SD_CMD_CRC_FAIL;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CCRCFAIL );

            return errorstate;
        }
        else
        {
            /* No error flag set */
        }

        /* Check response received is of desired command */
        if( SDIO_GetCommandResponse( hsd->Instance ) != SD_CMD )
        {
            FF_PRINTF( "RESPCMD[2] = %08x cmd = %02x\n", hsd->Instance->RESPCMD, SD_CMD );
            errorstate = SD_ILLEGAL_CMD;

            return errorstate;
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        /* We have received response, retrieve it.  */
        response_r1 = SDIO_GetResponse( hsd->Instance, SDIO_RESP1 );

        if( ( response_r1 & ( SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED ) ) == SD_ALLZERO )
        {
            *pRCA = ( uint16_t ) ( response_r1 >> 16 );

            return errorstate;
        }

        if( ( response_r1 & SD_R6_GENERAL_UNKNOWN_ERROR ) == SD_R6_GENERAL_UNKNOWN_ERROR )
        {
            return( SD_GENERAL_UNKNOWN_ERROR );
        }

        if( ( response_r1 & SD_R6_ILLEGAL_CMD ) == SD_R6_ILLEGAL_CMD )
        {
            FF_PRINTF( "response_r1 = %08x cmd = %02x\n", hsd->Instance->RESPCMD, SD_R6_ILLEGAL_CMD );
            return( SD_ILLEGAL_CMD );
        }

        if( ( response_r1 & SD_R6_COM_CRC_FAILED ) == SD_R6_COM_CRC_FAILED )
        {
            return( SD_COM_CRC_FAILED );
        }

        return errorstate;
    }

/**
 * @brief  Enables the SDMMC wide bus mode.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_WideBus_Enable( SD_HandleTypeDef * hsd )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;

        uint32_t scr[ 2 ] = { 0, 0 };

        if( ( SDIO_GetResponse( hsd->Instance, SDIO_RESP1 ) & SD_CARD_LOCKED ) == SD_CARD_LOCKED )
        {
            errorstate = SD_LOCK_UNLOCK_FAILED;

            return errorstate;
        }

        /* Get SCR Register */
        errorstate = SD_FindSCR( hsd, scr );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* If requested card supports wide bus operation */
        if( ( scr[ 1 ] & SD_WIDE_BUS_SUPPORT ) != SD_ALLZERO )
        {
            /* Send CMD55 APP_CMD with argument as card's RCA.*/
            sdmmc_cmdinitstructure.Argument = ( uint32_t ) ( hsd->RCA << 16 );
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD;
            sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
            sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
            sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp1Error( hsd, SD_CMD_APP_CMD );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            /* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */
            sdmmc_cmdinitstructure.Argument = 2;
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp1Error( hsd, SD_CMD_APP_SD_SET_BUSWIDTH );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            return errorstate;
        }
        else
        {
            errorstate = SD_REQUEST_NOT_APPLICABLE;

            return errorstate;
        }
    }

/**
 * @brief  Disables the SDMMC wide bus mode.
 * @param  hsd SD handle
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_WideBus_Disable( SD_HandleTypeDef * hsd )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;

        uint32_t scr[ 2 ] = { 0, 0 };

        if( ( SDIO_GetResponse( hsd->Instance, SDIO_RESP1 ) & SD_CARD_LOCKED ) == SD_CARD_LOCKED )
        {
            errorstate = SD_LOCK_UNLOCK_FAILED;

            return errorstate;
        }

        /* Get SCR Register */
        errorstate = SD_FindSCR( hsd, scr );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* If requested card supports 1 bit mode operation */
        if( ( scr[ 1 ] & SD_SINGLE_BUS_SUPPORT ) != SD_ALLZERO )
        {
            /* Send CMD55 APP_CMD with argument as card's RCA */
            sdmmc_cmdinitstructure.Argument = ( uint32_t ) ( hsd->RCA << 16 );
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD;
            sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
            sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
            sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp1Error( hsd, SD_CMD_APP_CMD );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            /* Send ACMD6 APP_CMD with argument as 0 for single bus mode */
            sdmmc_cmdinitstructure.Argument = 0;
            sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH;
            SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

            /* Check for error conditions */
            errorstate = SD_CmdResp1Error( hsd, SD_CMD_APP_SD_SET_BUSWIDTH );

            if( errorstate != SD_OK )
            {
                return errorstate;
            }

            return errorstate;
        }
        else
        {
            errorstate = SD_REQUEST_NOT_APPLICABLE;

            return errorstate;
        }
    }


/**
 * @brief  Finds the SD card SCR register value.
 * @param  hsd SD handle
 * @param  pSCR pointer to the buffer that will contain the SCR value
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_FindSCR( SD_HandleTypeDef * hsd,
                                           uint32_t * pSCR )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        SDIO_DataInitTypeDef sdmmc_datainitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        uint32_t index = 0;
        uint32_t tempscr[ 2 ] = { 0, 0 };

        /* Set Block Size To 8 Bytes */
        /* Send CMD55 APP_CMD with argument as card's RCA */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) 8;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SET_BLOCKLEN );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        /* Send CMD55 APP_CMD with argument as card's RCA */
        sdmmc_cmdinitstructure.Argument = ( uint32_t ) ( ( hsd->RCA ) << 16 );
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_APP_CMD );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT;
        sdmmc_datainitstructure.DataLength = 8;
        sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_8B;
        sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
        sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
        sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE;
        SDIO_DataConfig( hsd->Instance, &sdmmc_datainitstructure );

        /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */
        sdmmc_cmdinitstructure.Argument = 0;
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_SEND_SCR;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        /* Check for error conditions */
        errorstate = SD_CmdResp1Error( hsd, SD_CMD_SD_APP_SEND_SCR );

        if( errorstate != SD_OK )
        {
            return errorstate;
        }

        while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND ) )
        {
            if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXDAVL ) )
            {
                *( tempscr + index ) = SDIO_ReadFIFO( hsd->Instance );
                index++;
            }
        }

        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DTIMEOUT ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DTIMEOUT );

            errorstate = SD_DATA_TIMEOUT;

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_DCRCFAIL ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_DCRCFAIL );

            errorstate = SD_DATA_CRC_FAIL;

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_RXOVERR ) )
        {
            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_RXOVERR );

            errorstate = SD_RX_OVERRUN;

            return errorstate;
        }
        else
        {
            /* No error flag set */
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );

        *( pSCR + 1 ) = ( ( tempscr[ 0 ] & SD_0TO7BITS ) << 24 ) | ( ( tempscr[ 0 ] & SD_8TO15BITS ) << 8 ) | \
                        ( ( tempscr[ 0 ] & SD_16TO23BITS ) >> 8 ) | ( ( tempscr[ 0 ] & SD_24TO31BITS ) >> 24 );

        *( pSCR ) = ( ( tempscr[ 1 ] & SD_0TO7BITS ) << 24 ) | ( ( tempscr[ 1 ] & SD_8TO15BITS ) << 8 ) | \
                    ( ( tempscr[ 1 ] & SD_16TO23BITS ) >> 8 ) | ( ( tempscr[ 1 ] & SD_24TO31BITS ) >> 24 );

        return errorstate;
    }

/**
 * @brief  Checks if the SD card is in programming state.
 * @param  hsd SD handle
 * @param  pStatus pointer to the variable that will contain the SD card state
 * @retval SD Card error state
 */
    static HAL_SD_ErrorTypedef SD_IsCardProgramming( SD_HandleTypeDef * hsd,
                                                     uint8_t * pStatus )
    {
        SDIO_CmdInitTypeDef sdmmc_cmdinitstructure;
        HAL_SD_ErrorTypedef errorstate = SD_OK;
        __IO uint32_t responseR1 = 0;

        sdmmc_cmdinitstructure.Argument = ( uint32_t ) ( hsd->RCA << 16 );
        sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_STATUS;
        sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT;
        sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO;
        sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE;
        SDIO_SendCommand( hsd->Instance, &sdmmc_cmdinitstructure );

        while( !__HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT ) )
        {
        }

        if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CTIMEOUT ) )
        {
            errorstate = SD_CMD_RSP_TIMEOUT;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CTIMEOUT );

            return errorstate;
        }
        else if( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_CCRCFAIL ) )
        {
            errorstate = SD_CMD_CRC_FAIL;

            __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_FLAG_CCRCFAIL );

            return errorstate;
        }
        else
        {
            /* No error flag set */
        }

        /* Check response received is of desired command */
        if( ( uint32_t ) SDIO_GetCommandResponse( hsd->Instance ) != SD_CMD_SEND_STATUS )
        {
            FF_PRINTF( "RESPCMD[3] = %08x cmd = %02x\n", hsd->Instance->RESPCMD, SD_CMD_SEND_STATUS );
            errorstate = SD_ILLEGAL_CMD;

            return errorstate;
        }

        /* Clear all the static flags */
        __HAL_SD_SDIO_CLEAR_FLAG( hsd, SDIO_STATIC_FLAGS );


        /* We have received response, retrieve it for analysis */
        responseR1 = SDIO_GetResponse( hsd->Instance, SDIO_RESP1 );

        /* Find out card status */
        *pStatus = ( uint8_t ) ( ( responseR1 >> 9 ) & 0x0000000F );

        if( ( responseR1 & SD_OCR_ERRORBITS ) == SD_ALLZERO )
        {
            return errorstate;
        }

        if( ( responseR1 & SD_OCR_ADDR_OUT_OF_RANGE ) == SD_OCR_ADDR_OUT_OF_RANGE )
        {
            return( SD_ADDR_OUT_OF_RANGE );
        }

        if( ( responseR1 & SD_OCR_ADDR_MISALIGNED ) == SD_OCR_ADDR_MISALIGNED )
        {
            return( SD_ADDR_MISALIGNED );
        }

        if( ( responseR1 & SD_OCR_BLOCK_LEN_ERR ) == SD_OCR_BLOCK_LEN_ERR )
        {
            return( SD_BLOCK_LEN_ERR );
        }

        if( ( responseR1 & SD_OCR_ERASE_SEQ_ERR ) == SD_OCR_ERASE_SEQ_ERR )
        {
            return( SD_ERASE_SEQ_ERR );
        }

        if( ( responseR1 & SD_OCR_BAD_ERASE_PARAM ) == SD_OCR_BAD_ERASE_PARAM )
        {
            return( SD_BAD_ERASE_PARAM );
        }

        if( ( responseR1 & SD_OCR_WRITE_PROT_VIOLATION ) == SD_OCR_WRITE_PROT_VIOLATION )
        {
            return( SD_WRITE_PROT_VIOLATION );
        }

        if( ( responseR1 & SD_OCR_LOCK_UNLOCK_FAILED ) == SD_OCR_LOCK_UNLOCK_FAILED )
        {
            return( SD_LOCK_UNLOCK_FAILED );
        }

        if( ( responseR1 & SD_OCR_COM_CRC_FAILED ) == SD_OCR_COM_CRC_FAILED )
        {
            return( SD_COM_CRC_FAILED );
        }

        if( ( responseR1 & SD_OCR_ILLEGAL_CMD ) == SD_OCR_ILLEGAL_CMD )
        {
            return( SD_ILLEGAL_CMD );
        }

        if( ( responseR1 & SD_OCR_CARD_ECC_FAILED ) == SD_OCR_CARD_ECC_FAILED )
        {
            return( SD_CARD_ECC_FAILED );
        }

        if( ( responseR1 & SD_OCR_CC_ERROR ) == SD_OCR_CC_ERROR )
        {
            return( SD_CC_ERROR );
        }

        if( ( responseR1 & SD_OCR_GENERAL_UNKNOWN_ERROR ) == SD_OCR_GENERAL_UNKNOWN_ERROR )
        {
            return( SD_GENERAL_UNKNOWN_ERROR );
        }

        if( ( responseR1 & SD_OCR_STREAM_READ_UNDERRUN ) == SD_OCR_STREAM_READ_UNDERRUN )
        {
            return( SD_STREAM_READ_UNDERRUN );
        }

        if( ( responseR1 & SD_OCR_STREAM_WRITE_OVERRUN ) == SD_OCR_STREAM_WRITE_OVERRUN )
        {
            return( SD_STREAM_WRITE_OVERRUN );
        }

        if( ( responseR1 & SD_OCR_CID_CSD_OVERWRITE ) == SD_OCR_CID_CSD_OVERWRITE )
        {
            return( SD_CID_CSD_OVERWRITE );
        }

        if( ( responseR1 & SD_OCR_WP_ERASE_SKIP ) == SD_OCR_WP_ERASE_SKIP )
        {
            return( SD_WP_ERASE_SKIP );
        }

        if( ( responseR1 & SD_OCR_CARD_ECC_DISABLED ) == SD_OCR_CARD_ECC_DISABLED )
        {
            return( SD_CARD_ECC_DISABLED );
        }

        if( ( responseR1 & SD_OCR_ERASE_RESET ) == SD_OCR_ERASE_RESET )
        {
            return( SD_ERASE_RESET );
        }

        if( ( responseR1 & SD_OCR_AKE_SEQ_ERROR ) == SD_OCR_AKE_SEQ_ERROR )
        {
            return( SD_AKE_SEQ_ERROR );
        }

        return errorstate;
    }

/**
 * @}
 */

#endif /* HAL_SD_MODULE_ENABLED */

/**
 * @}
 */

/**
 * @}
 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
